[Console] Add request/response DTOs for all REST controllers (#4475)

[Console] Complete REST API DTO and typed response contract refactor

Refactor the console-service REST API layer to establish explicit and
type-safe request/response contracts instead of exposing domain entities
directly through HTTP endpoints.

This change introduces dedicated request and response DTOs across the
Console REST controllers, together with assembler-based mappings between
API DTOs and domain entities. It also completes the migration to typed
RestResponseBody responses while keeping HTTP-specific response wrapping
at the Controller boundary.

Key changes:

* Introduce dedicated request/response DTOs across Flink, Spark, resource,
  setting, system, project, variable, alert, and other REST APIs.

* Replace direct domain entity pass-through at HTTP boundaries with explicit
  DTO contracts and introduce DtoAssembler and domain-specific assemblers
  for request/entity/response conversion.

* Add Bean Validation constraints to request DTOs and apply @Valid across
  controller endpoints, including common ID/team requests, application,
  cluster, environment, project, resource, variable, alert, configuration,
  savepoint, and system APIs.

* Add spring-boot-starter-validation to enable Bean Validation and register
  the related dependencies for backend license verification.

* Introduce typed RestResponseBody responses and replace wildcard/Object
  payloads with concrete response DTOs, primitives, and domain result types
  wherever possible.

* Keep RestResponseBody and other HTTP-specific response semantics at the
  Controller layer. Service methods now return domain result types instead
  of HTTP response envelopes.

* Preserve compatibility with existing clients by introducing @FormOrJson
  request binding for endpoints that need to accept both JSON and legacy
  form-urlencoded requests.

* Preserve legacy response formats where required, including login response
  codes, build log extension fields, token creation responses, alert config
  JSON-string parameters, and SQL endpoints with object-or-array payloads.

* Improve OpenAPI generation by deriving request schemas from DTO fields
  through RequestDtoSchemaBuilder and update OpenAPIAspect and
  PermissionAspect for RestResponseBody compatibility.

* Add shared request models such as SqlVerifyRequest,
  AppScopedIdRequest, and AppTeamQueryRequest to reduce duplicated API
  contracts and validation logic.

* Add null-safety guards around assembler, environment, SQL, resource, and
  cluster paths and fix related Sonar reliability findings.

* Resolve Sonar issues around response generics, null dereferences, duplicated
  literals, collection returns, serialization, and code complexity.

* Expand validation unit tests and WebMvcTest coverage for Flink application,
  system, setting, application-scoped, SQL, and other REST endpoints.

* Fix compatibility regressions discovered by E2E tests, including resource
  assembly, alert name checks, Yarn queue validation, and alert configuration
  serialization.

* Apply Spotless formatting and update known dependency licenses required by
  backend CI verification.

The refactor keeps the existing REST API behavior compatible where required
while establishing a clearer separation between API contracts, domain models,
service results, and HTTP response representations. This provides a stronger
foundation for validation, OpenAPI schema generation, API type export, and
future frontend/backend contract evolution.
diff --git a/streampark-console/streampark-console-service/pom.xml b/streampark-console/streampark-console-service/pom.xml
index 1394335..b82cd03 100644
--- a/streampark-console/streampark-console-service/pom.xml
+++ b/streampark-console/streampark-console-service/pom.xml
@@ -142,6 +142,11 @@
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-undertow</artifactId>
         </dependency>
 
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/config/WebMvcConfig.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/config/WebMvcConfig.java
index 0abaa97..06e3035 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/config/WebMvcConfig.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/config/WebMvcConfig.java
@@ -18,6 +18,7 @@
 package org.apache.streampark.console.base.config;
 
 import org.apache.streampark.console.base.interceptor.UploadFileTypeInterceptor;
+import org.apache.streampark.console.base.web.FormOrJsonArgumentResolver;
 
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.module.SimpleModule;
@@ -31,6 +32,7 @@
 import org.springframework.http.converter.ResourceHttpMessageConverter;
 import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -44,6 +46,9 @@
     @Autowired
     private UploadFileTypeInterceptor uploadFileTypeInterceptor;
 
+    @Autowired
+    private FormOrJsonArgumentResolver formOrJsonArgumentResolver;
+
     private static final String[] CORS_MAPPINGS_ALLOWED_METHODS = {
             HttpMethod.POST.name(),
             HttpMethod.GET.name(),
@@ -95,4 +100,9 @@
             .addInterceptor(uploadFileTypeInterceptor)
             .addPathPatterns("/flink/app/upload", "/resource/upload");
     }
+
+    @Override
+    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
+        resolvers.add(formOrJsonArgumentResolver);
+    }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponse.java
index b41eb23..912d97a 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponse.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponse.java
@@ -23,6 +23,14 @@
 
 import java.util.HashMap;
 
+/**
+ * Legacy REST envelope based on a {@link HashMap}. Prefer {@link RestResponseBody} at controller
+ * boundaries; this type remains for internal transitions and compatibility helpers.
+ *
+ * @deprecated Use {@link RestResponseBody} for controller return types.
+ */
+@Deprecated(since = "3.0.0")
+@SuppressWarnings("java:S1133")
 public class RestResponse extends HashMap<String, Object> {
 
     public static final String STATUS_SUCCESS = "success";
@@ -40,6 +48,25 @@
         return resp;
     }
 
+    /**
+     * Returns the {@code data} payload cast to the requested type.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T getDataAs(Class<T> type) {
+        Object data = get(DATA_KEY);
+        if (data == null) {
+            return null;
+        }
+        return type.cast(data);
+    }
+
+    /**
+     * Wraps this response in a typed {@link RestResponseBody}.
+     */
+    public <T> RestResponseBody<T> asBody() {
+        return RestResponseBody.from(this);
+    }
+
     public static RestResponse success() {
         RestResponse resp = new RestResponse();
         resp.put(STATUS_KEY, STATUS_SUCCESS);
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponseBody.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponseBody.java
new file mode 100644
index 0000000..659b93a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/domain/RestResponseBody.java
@@ -0,0 +1,145 @@
+/*
+ * 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 org.apache.streampark.console.base.domain;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
+import org.slf4j.helpers.MessageFormatter;
+
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Typed REST envelope replacing raw {@link RestResponse} at controller boundaries.
+ *
+ * <p>Wire JSON shape is unchanged: {@code status}, {@code code}, optional {@code message}, optional
+ * {@code data}. Additional top-level keys from legacy {@link RestResponse} maps are supported via
+ * {@link #extra(String, Object)} and serialize through {@link #getExtensions()}.
+ *
+ * @param <T> payload type
+ */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class RestResponseBody<T> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String status;
+
+    private Long code;
+
+    private String message;
+
+    private T data;
+
+    @JsonIgnore
+    private Map<String, Object> extensions;
+
+    public static <T> RestResponseBody<T> success(T data) {
+        RestResponseBody<T> body = new RestResponseBody<>();
+        body.setStatus(RestResponse.STATUS_SUCCESS);
+        body.setCode(ResponseCode.CODE_SUCCESS);
+        body.setData(data);
+        return body;
+    }
+
+    public static RestResponseBody<Void> success() {
+        return success(null);
+    }
+
+    public static <T> RestResponseBody<T> fail(Long code, String format, Object... args) {
+        String message = MessageFormatter.arrayFormat(format, args).getMessage();
+        return fail(code, message);
+    }
+
+    public static <T> RestResponseBody<T> fail(Long code, String message) {
+        RestResponseBody<T> body = new RestResponseBody<>();
+        body.setStatus(RestResponse.STATUS_FAIL);
+        body.setCode(code);
+        body.setMessage(message);
+        body.setData(null);
+        return body;
+    }
+
+    public RestResponseBody<T> message(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public RestResponseBody<T> data(T data) {
+        this.data = data;
+        return this;
+    }
+
+    public RestResponseBody<T> extra(String key, Object value) {
+        if (extensions == null) {
+            extensions = new LinkedHashMap<>();
+        }
+        extensions.put(key, value);
+        if (RestResponse.CODE_KEY.equals(key) && value instanceof Number) {
+            this.code = ((Number) value).longValue();
+        }
+        return this;
+    }
+
+    @JsonAnyGetter
+    public Map<String, Object> getExtensions() {
+        return extensions;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> RestResponseBody<T> from(RestResponse response) {
+        RestResponseBody<T> body = new RestResponseBody<>();
+        if (response == null) {
+            return body;
+        }
+        body.setStatus((String) response.get(RestResponse.STATUS_KEY));
+        body.setCode((Long) response.get(RestResponse.CODE_KEY));
+        body.setMessage((String) response.get(RestResponse.MESSAGE_KEY));
+        body.setData((T) response.get(RestResponse.DATA_KEY));
+        for (Map.Entry<String, Object> entry : response.entrySet()) {
+            String key = entry.getKey();
+            if (RestResponse.STATUS_KEY.equals(key)
+                || RestResponse.CODE_KEY.equals(key)
+                || RestResponse.MESSAGE_KEY.equals(key)
+                || RestResponse.DATA_KEY.equals(key)) {
+                continue;
+            }
+            body.extra(key, entry.getValue());
+        }
+        return body;
+    }
+
+    public RestResponse toRestResponse() {
+        RestResponse response = new RestResponse();
+        response.put(RestResponse.STATUS_KEY, status);
+        response.put(RestResponse.CODE_KEY, code);
+        if (message != null) {
+            response.put(RestResponse.MESSAGE_KEY, message);
+        }
+        response.put(RestResponse.DATA_KEY, data);
+        if (extensions != null) {
+            response.putAll(extensions);
+        }
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/handler/GlobalExceptionHandler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/handler/GlobalExceptionHandler.java
index edbe8f7..7062968 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/handler/GlobalExceptionHandler.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/handler/GlobalExceptionHandler.java
@@ -19,7 +19,7 @@
 
 import org.apache.streampark.common.util.ExceptionUtils;
 import org.apache.streampark.console.base.domain.ResponseCode;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.AbstractApiException;
 
 import org.apache.commons.lang3.StringUtils;
@@ -33,6 +33,7 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.validation.BindException;
 import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -51,34 +52,45 @@
 
     @ExceptionHandler(value = UnauthenticatedException.class)
     @ResponseStatus(HttpStatus.UNAUTHORIZED)
-    public RestResponse handelUnauthenticatedException(UnauthenticatedException e) {
+    public RestResponseBody<Void> handelUnauthenticatedException(UnauthenticatedException e) {
         log.error("Unauthenticated.", e);
-        return RestResponse.fail(ResponseCode.CODE_UNAUTHORIZED, "Unauthenticated.");
+        return RestResponseBody.fail(ResponseCode.CODE_UNAUTHORIZED, "Unauthenticated.");
     }
 
     @ExceptionHandler(value = AuthenticationException.class)
     @ResponseStatus(HttpStatus.UNAUTHORIZED)
-    public RestResponse handelUnauthenticatedException(AuthenticationException e) {
+    public RestResponseBody<Void> handelUnauthenticatedException(AuthenticationException e) {
         log.error("Permission denied.", e);
-        return RestResponse.fail(ResponseCode.CODE_UNAUTHORIZED, "Permission denied.");
+        return RestResponseBody.fail(ResponseCode.CODE_UNAUTHORIZED, "Permission denied.");
     }
 
     @ExceptionHandler(value = AbstractApiException.class)
     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
-    public RestResponse handleException(AbstractApiException e) {
+    public RestResponseBody<Void> handleException(AbstractApiException e) {
         log.error("api exception:", e);
-        return RestResponse.fail(e.getResponseCode(), e.getMessage());
+        return RestResponseBody.fail(e.getResponseCode(), e.getMessage());
     }
 
     @ExceptionHandler(value = Exception.class)
     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     @Order(value = Ordered.HIGHEST_PRECEDENCE)
-    public RestResponse handleException(Exception e) {
+    public RestResponseBody<Void> handleException(Exception e) {
         log.error("internal server error:", e);
-        return RestResponse.fail(
+        return RestResponseBody.fail(
             ResponseCode.CODE_FAIL, "internal server error: " + ExceptionUtils.stringifyException(e));
     }
 
+    private static String formatFieldErrors(List<FieldError> fieldErrors) {
+        if (fieldErrors == null || fieldErrors.isEmpty()) {
+            return "";
+        }
+        StringBuilder message = new StringBuilder();
+        for (FieldError error : fieldErrors) {
+            message.append(error.getField()).append(error.getDefaultMessage()).append(StringPool.COMMA);
+        }
+        return message.substring(0, message.length() - 1);
+    }
+
     /**
      * Unified processing of request parameter verification (entity object parameter transfer)
      *
@@ -87,35 +99,43 @@
      */
     @ExceptionHandler(BindException.class)
     @ResponseStatus(HttpStatus.BAD_REQUEST)
-    public RestResponse validExceptionHandler(BindException e) {
+    public RestResponseBody<Void> validExceptionHandler(BindException e) {
         log.error("bind exception:", e);
-        StringBuilder message = new StringBuilder();
-        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
-        for (FieldError error : fieldErrors) {
-            message.append(error.getField()).append(error.getDefaultMessage()).append(StringPool.COMMA);
-        }
-        message = new StringBuilder(message.substring(0, message.length() - 1));
-        return RestResponse.fail(ResponseCode.CODE_FAIL, message.toString());
+        return RestResponseBody.fail(ResponseCode.CODE_FAIL, formatFieldErrors(e.getBindingResult().getFieldErrors()));
+    }
+
+    /**
+     * Unified processing of request parameter verification ({@code @RequestBody} JSON).
+     *
+     * @param e MethodArgumentNotValidException
+     * @return RestResponseBody
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public RestResponseBody<Void> methodArgumentNotValidHandler(MethodArgumentNotValidException e) {
+        log.error("method argument not valid exception:", e);
+        return RestResponseBody.fail(ResponseCode.CODE_FAIL, formatFieldErrors(e.getBindingResult().getFieldErrors()));
     }
 
     /**
      * Unified processing of request parameter verification (ordinary parameter transfer)
      *
      * @param e ConstraintViolationException
-     * @return RestResponse
+     * @return RestResponseBody
      */
     @ExceptionHandler(value = ConstraintViolationException.class)
     @ResponseStatus(HttpStatus.BAD_REQUEST)
-    public RestResponse handleConstraintViolationException(ConstraintViolationException e) {
+    public RestResponseBody<Void> handleConstraintViolationException(ConstraintViolationException e) {
         log.error("constraint violation exception:", e);
         StringBuilder message = new StringBuilder();
         Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
         for (ConstraintViolation<?> violation : violations) {
             Path path = violation.getPropertyPath();
             String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), StringPool.DOT);
-            message.append(pathArr[1]).append(violation.getMessage()).append(StringPool.COMMA);
+            String field = pathArr.length > 1 ? pathArr[pathArr.length - 1] : pathArr[0];
+            message.append(field).append(violation.getMessage()).append(StringPool.COMMA);
         }
         message = new StringBuilder(message.substring(0, message.length() - 1));
-        return RestResponse.fail(ResponseCode.CODE_FAIL, message.toString());
+        return RestResponseBody.fail(ResponseCode.CODE_FAIL, message.toString());
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJson.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJson.java
new file mode 100644
index 0000000..6af0734
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJson.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.base.web;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Binds a request DTO from {@code application/x-www-form-urlencoded} or {@code application/json}
+ * depending on the incoming {@code Content-Type}.
+ *
+ * <p>Does not support {@code multipart/form-data}; file upload endpoints should use dedicated
+ * binding. The target DTO must expose a no-arg constructor for form binding.
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface FormOrJson {
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolver.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolver.java
new file mode 100644
index 0000000..1757578
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolver.java
@@ -0,0 +1,99 @@
+/*
+ * 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 org.apache.streampark.console.base.web;
+
+import org.apache.streampark.console.base.exception.ApiAlertException;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.core.MethodParameter;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.ServletRequestDataBinder;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Valid;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+/** Resolves {@link FormOrJson} controller parameters from form fields or JSON body. */
+@Component
+public class FormOrJsonArgumentResolver implements HandlerMethodArgumentResolver {
+
+    private final ObjectMapper objectMapper;
+    private final Validator validator;
+
+    public FormOrJsonArgumentResolver(ObjectMapper objectMapper, Validator validator) {
+        this.objectMapper = objectMapper;
+        this.validator = validator;
+    }
+
+    @Override
+    public boolean supportsParameter(MethodParameter parameter) {
+        return parameter.hasParameterAnnotation(FormOrJson.class);
+    }
+
+    @Override
+    public Object resolveArgument(
+                                  MethodParameter parameter,
+                                  ModelAndViewContainer mavContainer,
+                                  NativeWebRequest webRequest,
+                                  org.springframework.web.bind.support.WebDataBinderFactory binderFactory) throws Exception {
+        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
+        Class<?> targetType = parameter.getParameterType();
+        Object target;
+        if (isJsonRequest(request)) {
+            target = objectMapper.readValue(request.getInputStream(), targetType);
+        } else {
+            try {
+                target = targetType.getDeclaredConstructor().newInstance();
+            } catch (ReflectiveOperationException e) {
+                throw new ApiAlertException(
+                    "Request DTO must have a no-arg constructor for form binding: " + targetType.getName(), e);
+            }
+            ServletRequestDataBinder binder = new ServletRequestDataBinder(target, parameter.getParameterName());
+            binder.bind(request);
+            if (binder.getBindingResult().hasErrors()) {
+                throw new BindException(binder.getBindingResult());
+            }
+        }
+        if (parameter.hasParameterAnnotation(Valid.class)) {
+            validateTarget(target);
+        }
+        return target;
+    }
+
+    private static boolean isJsonRequest(HttpServletRequest request) {
+        String contentType = request.getContentType();
+        return StringUtils.isNotBlank(contentType) && contentType.toLowerCase().contains("application/json");
+    }
+
+    private void validateTarget(Object target) {
+        Set<ConstraintViolation<Object>> violations = validator.validate(target);
+        if (!violations.isEmpty()) {
+            throw new ConstraintViolationException(violations);
+        }
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiParam.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiParam.java
new file mode 100644
index 0000000..a44f299
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/ApiParam.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 org.apache.streampark.console.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Documents a request DTO field for OpenAPI schema generation and external API naming.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ApiParam {
+
+    /** Human-readable description shown in OpenAPI schema. */
+    String description() default "";
+
+    /**
+     * External parameter name in form submissions. When empty, the Java field name is used.
+     */
+    String name() default "";
+
+    /** Whether the parameter is required in the public API contract. */
+    boolean required() default false;
+
+    /** Default value hint for optional parameters. */
+    String defaultValue() default "";
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/OpenAPIAspect.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/OpenAPIAspect.java
index 2438802..e7142ae 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/OpenAPIAspect.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/OpenAPIAspect.java
@@ -19,7 +19,6 @@
 
 import org.apache.streampark.common.util.DateUtils;
 import org.apache.streampark.common.util.ReflectUtils;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.core.annotation.OpenAPI;
 import org.apache.streampark.console.system.entity.AccessToken;
@@ -48,15 +47,13 @@
 @Aspect
 public class OpenAPIAspect {
 
-    @Pointcut("execution(public"
-        + " org.apache.streampark.console.base.domain.RestResponse"
-        + " org.apache.streampark.console.core.controller.*.*(..))")
+    @Pointcut("@annotation(org.apache.streampark.console.core.annotation.OpenAPI)")
     public void openAPIPointcut() {
     }
 
     @SuppressWarnings("checkstyle:SimplifyBooleanExpression")
     @Around(value = "openAPIPointcut()")
-    public RestResponse openAPI(ProceedingJoinPoint joinPoint) throws Throwable {
+    public Object openAPI(ProceedingJoinPoint joinPoint) throws Throwable {
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
         log.debug("restResponse aspect, method:{}", methodSignature.getName());
         Boolean isApi = (Boolean) SecurityUtils.getSubject().getSession().getAttribute(AccessToken.IS_API_TOKEN);
@@ -65,40 +62,58 @@
                 ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
             OpenAPI openAPI = methodSignature.getMethod().getAnnotation(OpenAPI.class);
             if (openAPI == null) {
-                String url = request.getRequestURI();
-                throw new ApiAlertException("openapi unsupported: " + url);
-            } else {
-                Object[] objects = joinPoint.getArgs();
-                for (OpenAPI.Param param : openAPI.param()) {
-                    String bingFor = param.bindFor();
-                    if (StringUtils.isNotBlank(bingFor)) {
-                        String name = param.name();
-                        for (Object args : objects) {
-                            Field bindForField = ReflectUtils.getField(args.getClass(), bingFor);
-                            if (bindForField != null) {
-                                Object value = request.getParameter(name);
-                                bindForField.setAccessible(true);
-                                if (value != null) {
-                                    if (param.type().equals(String.class)) {
-                                        bindForField.set(args, value.toString());
-                                    } else if (param.type().equals(Boolean.class)
-                                        || param.type().equals(boolean.class)) {
-                                        bindForField.set(args, Boolean.parseBoolean(value.toString()));
-                                    } else if (param.type().equals(Integer.class) || param.type().equals(int.class)) {
-                                        bindForField.set(args, Integer.parseInt(value.toString()));
-                                    } else if (param.type().equals(Long.class) || param.type().equals(long.class)) {
-                                        bindForField.set(args, Long.parseLong(value.toString()));
-                                    } else if (param.type().equals(Date.class)) {
-                                        bindForField.set(args, DateUtils.parse(value.toString(), DateUtils.fullFormat(),
-                                            TimeZone.getDefault()));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+                throw new ApiAlertException("openapi unsupported: " + request.getRequestURI());
             }
+            bindOpenApiParameters(request, openAPI, joinPoint.getArgs());
         }
-        return (RestResponse) joinPoint.proceed();
+        return joinPoint.proceed();
+    }
+
+    private void bindOpenApiParameters(HttpServletRequest request, OpenAPI openAPI,
+                                       Object[] args) throws Exception {
+        for (OpenAPI.Param param : openAPI.param()) {
+            bindOpenApiParameter(request, param, args);
+        }
+    }
+
+    private void bindOpenApiParameter(HttpServletRequest request, OpenAPI.Param param,
+                                      Object[] args) throws Exception {
+        String bindFor = param.bindFor();
+        if (StringUtils.isBlank(bindFor)) {
+            return;
+        }
+        String name = param.name();
+        for (Object arg : args) {
+            Field bindForField = ReflectUtils.getField(arg.getClass(), bindFor);
+            if (bindForField == null) {
+                continue;
+            }
+            String value = request.getParameter(name);
+            if (value == null) {
+                continue;
+            }
+            bindForField.setAccessible(true);
+            bindForField.set(arg, convertParameterValue(param, value));
+        }
+    }
+
+    private Object convertParameterValue(OpenAPI.Param param, String value) throws Exception {
+        Class<?> type = param.type();
+        if (type.equals(String.class)) {
+            return value;
+        }
+        if (type.equals(Boolean.class) || type.equals(boolean.class)) {
+            return Boolean.parseBoolean(value);
+        }
+        if (type.equals(Integer.class) || type.equals(int.class)) {
+            return Integer.parseInt(value);
+        }
+        if (type.equals(Long.class) || type.equals(long.class)) {
+            return Long.parseLong(value);
+        }
+        if (type.equals(Date.class)) {
+            return DateUtils.parse(value, DateUtils.fullFormat(), TimeZone.getDefault());
+        }
+        return value;
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java
index 698e023..7553974 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java
@@ -17,7 +17,6 @@
 
 package org.apache.streampark.console.core.aspect;
 
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.core.annotation.Permission;
 import org.apache.streampark.console.core.entity.FlinkApplication;
@@ -60,7 +59,7 @@
     }
 
     @Around("permissionPointcut()")
-    public RestResponse permissionAction(ProceedingJoinPoint joinPoint) throws Throwable {
+    public Object permissionAction(ProceedingJoinPoint joinPoint) throws Throwable {
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
         Permission permission = methodSignature.getMethod().getAnnotation(Permission.class);
 
@@ -99,7 +98,7 @@
             }
         }
 
-        return (RestResponse) joinPoint.proceed();
+        return joinPoint.proceed();
     }
 
     private Long getId(ProceedingJoinPoint joinPoint, MethodSignature methodSignature, String expr) {
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AlertAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AlertAssembler.java
new file mode 100644
index 0000000..01e391c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AlertAssembler.java
@@ -0,0 +1,132 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.base.util.JacksonUtils;
+import org.apache.streampark.console.core.bean.AlertDingTalkParams;
+import org.apache.streampark.console.core.bean.AlertEmailParams;
+import org.apache.streampark.console.core.bean.AlertHttpCallbackParams;
+import org.apache.streampark.console.core.bean.AlertLarkParams;
+import org.apache.streampark.console.core.bean.AlertWeComParams;
+import org.apache.streampark.console.core.entity.AlertConfig;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
+import org.apache.streampark.console.core.response.alert.AlertConfigResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+
+/** Converts between alert config entities and API request/response contracts. */
+public final class AlertAssembler {
+
+    private AlertAssembler() {
+    }
+
+    public static AlertConfig toEntity(AlertConfigRequest request) {
+        if (request == null) {
+            return null;
+        }
+        AlertConfig alertConfig = new AlertConfig();
+        BeanUtils.copyProperties(
+            request,
+            alertConfig,
+            "emailParams",
+            "dingTalkParams",
+            "weComParams",
+            "httpCallbackParams",
+            "larkParams");
+        try {
+            if (request.getEmailParams() != null) {
+                alertConfig.setEmailParams(JacksonUtils.write(request.getEmailParams()));
+            }
+            if (request.getDingTalkParams() != null) {
+                alertConfig.setDingTalkParams(JacksonUtils.write(request.getDingTalkParams()));
+            }
+            if (request.getWeComParams() != null) {
+                alertConfig.setWeComParams(JacksonUtils.write(request.getWeComParams()));
+            }
+            if (request.getHttpCallbackParams() != null) {
+                alertConfig.setHttpCallbackParams(JacksonUtils.write(request.getHttpCallbackParams()));
+            }
+            if (request.getLarkParams() != null) {
+                alertConfig.setLarkParams(JacksonUtils.write(request.getLarkParams()));
+            }
+        } catch (JsonProcessingException e) {
+            throw new IllegalStateException("Failed to serialize alert config params", e);
+        }
+        return alertConfig;
+    }
+
+    public static AlertConfigResponse toResponse(AlertConfig config) {
+        if (config == null) {
+            return null;
+        }
+        AlertConfigResponse response = new AlertConfigResponse();
+        BeanUtils.copyProperties(config, response);
+        return response;
+    }
+
+    public static AlertConfigRequest toRequest(AlertConfig config) {
+        if (config == null) {
+            return null;
+        }
+        AlertConfigRequest request = new AlertConfigRequest();
+        BeanUtils.copyProperties(
+            config,
+            request,
+            "emailParams",
+            "dingTalkParams",
+            "weComParams",
+            "httpCallbackParams",
+            "larkParams");
+        try {
+            if (StringUtils.isNotBlank(config.getEmailParams())) {
+                request.setEmailParams(JacksonUtils.read(config.getEmailParams(), AlertEmailParams.class));
+            }
+            if (StringUtils.isNotBlank(config.getDingTalkParams())) {
+                request.setDingTalkParams(
+                    JacksonUtils.read(config.getDingTalkParams(), AlertDingTalkParams.class));
+            }
+            if (StringUtils.isNotBlank(config.getWeComParams())) {
+                request.setWeComParams(JacksonUtils.read(config.getWeComParams(), AlertWeComParams.class));
+            }
+            if (StringUtils.isNotBlank(config.getHttpCallbackParams())) {
+                request.setHttpCallbackParams(
+                    JacksonUtils.read(config.getHttpCallbackParams(), AlertHttpCallbackParams.class));
+            }
+            if (StringUtils.isNotBlank(config.getLarkParams())) {
+                request.setLarkParams(JacksonUtils.read(config.getLarkParams(), AlertLarkParams.class));
+            }
+        } catch (JsonProcessingException e) {
+            throw new IllegalStateException("Failed to deserialize alert config params", e);
+        }
+        return request;
+    }
+
+    public static IPage<AlertConfigResponse> toPageResponse(IPage<AlertConfig> page) {
+        return DtoAssembler.toPage(page, AlertAssembler::toResponse);
+    }
+
+    public static List<AlertConfigResponse> toListResponse(List<AlertConfig> configs) {
+        return DtoAssembler.toList(configs, AlertAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AppLogAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AppLogAssembler.java
new file mode 100644
index 0000000..6c39a7a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/AppLogAssembler.java
@@ -0,0 +1,92 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.ApplicationLog;
+import org.apache.streampark.console.core.entity.FlinkApplicationBackup;
+import org.apache.streampark.console.core.request.app.AppBackupDeleteRequest;
+import org.apache.streampark.console.core.request.app.AppBackupQueryRequest;
+import org.apache.streampark.console.core.request.app.AppOptLogDeleteRequest;
+import org.apache.streampark.console.core.request.app.AppOptLogQueryRequest;
+import org.apache.streampark.console.core.response.app.AppBackupResponse;
+import org.apache.streampark.console.core.response.app.AppOptLogResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+public final class AppLogAssembler {
+
+    private AppLogAssembler() {
+    }
+
+    public static FlinkApplicationBackup toEntity(AppBackupQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplicationBackup backup = new FlinkApplicationBackup();
+        backup.setAppId(request.getAppId());
+        backup.setTeamId(request.getTeamId());
+        return backup;
+    }
+
+    public static FlinkApplicationBackup toEntity(AppBackupDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplicationBackup backup = new FlinkApplicationBackup();
+        backup.setId(request.getId());
+        backup.setAppId(request.getAppId());
+        return backup;
+    }
+
+    public static ApplicationLog toEntity(AppOptLogQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        ApplicationLog log = new ApplicationLog();
+        log.setAppId(request.getAppId());
+        log.setTeamId(request.getTeamId());
+        return log;
+    }
+
+    public static ApplicationLog toEntity(AppOptLogDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        ApplicationLog log = new ApplicationLog();
+        log.setId(request.getId());
+        log.setAppId(request.getAppId());
+        log.setTeamId(request.getTeamId());
+        return log;
+    }
+
+    public static AppBackupResponse toResponse(FlinkApplicationBackup backup) {
+        return DtoAssembler.toDto(backup, AppBackupResponse.class);
+    }
+
+    public static AppOptLogResponse toResponse(ApplicationLog log) {
+        return DtoAssembler.toDto(log, AppOptLogResponse.class);
+    }
+
+    public static IPage<AppBackupResponse> toBackupPage(IPage<FlinkApplicationBackup> page) {
+        return DtoAssembler.toPage(page, AppLogAssembler::toResponse);
+    }
+
+    public static IPage<AppOptLogResponse> toOptLogPage(IPage<ApplicationLog> page) {
+        return DtoAssembler.toPage(page, AppLogAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/DtoAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/DtoAssembler.java
new file mode 100644
index 0000000..c3de9b2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/DtoAssembler.java
@@ -0,0 +1,73 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.beans.BeanUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/** Generic bean-copy helpers for request/response DTO mapping. */
+public final class DtoAssembler {
+
+    private DtoAssembler() {
+    }
+
+    public static <S, T> T toDto(S source, Class<T> targetClass) {
+        if (source == null) {
+            return null;
+        }
+        try {
+            T target = targetClass.getDeclaredConstructor().newInstance();
+            BeanUtils.copyProperties(source, target);
+            return target;
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalStateException("Failed to copy properties to " + targetClass.getName(), e);
+        }
+    }
+
+    public static <S, T> T map(S source, Function<S, T> mapper) {
+        return source == null ? null : mapper.apply(source);
+    }
+
+    public static <S, T> List<T> toList(List<S> sources, Function<S, T> mapper) {
+        if (sources == null) {
+            return Collections.emptyList();
+        }
+        return sources.stream().map(mapper).collect(Collectors.toList());
+    }
+
+    public static <S, T> IPage<T> toPage(IPage<S> page, Function<S, T> mapper) {
+        if (page == null) {
+            return null;
+        }
+        Page<T> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+        result.setRecords(toList(page.getRecords(), mapper));
+        return result;
+    }
+
+    public static <S, T> void copy(S source, T target) {
+        if (source != null && target != null) {
+            BeanUtils.copyProperties(source, target);
+        }
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ExternalLinkAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ExternalLinkAssembler.java
new file mode 100644
index 0000000..bcb06ed
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ExternalLinkAssembler.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.ExternalLink;
+import org.apache.streampark.console.core.request.externallink.ExternalLinkCreateRequest;
+import org.apache.streampark.console.core.request.externallink.ExternalLinkUpdateRequest;
+import org.apache.streampark.console.core.response.externallink.ExternalLinkResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+
+/** Converts between external link entities and API request/response contracts. */
+public final class ExternalLinkAssembler {
+
+    private ExternalLinkAssembler() {
+    }
+
+    public static ExternalLink toEntity(ExternalLinkCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        ExternalLink externalLink = new ExternalLink();
+        BeanUtils.copyProperties(request, externalLink);
+        return externalLink;
+    }
+
+    public static ExternalLink toEntity(ExternalLinkUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        ExternalLink externalLink = toEntity((ExternalLinkCreateRequest) request);
+        externalLink.setId(request.getId());
+        return externalLink;
+    }
+
+    public static ExternalLinkResponse toResponse(ExternalLink externalLink) {
+        return DtoAssembler.toDto(externalLink, ExternalLinkResponse.class);
+    }
+
+    public static List<ExternalLinkResponse> toListResponse(List<ExternalLink> externalLinks) {
+        return DtoAssembler.toList(externalLinks, ExternalLinkAssembler::toResponse);
+    }
+
+    public static IPage<ExternalLinkResponse> toPageResponse(IPage<ExternalLink> page) {
+        return DtoAssembler.toPage(page, ExternalLinkAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssembler.java
new file mode 100644
index 0000000..ed25884
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssembler.java
@@ -0,0 +1,221 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.metrics.flink.JobsOverview;
+import org.apache.streampark.console.core.request.flink.FlinkAppCancelRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCheckNameRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCheckSavepointPathRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppConfigRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCopyRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppGetMainRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppListQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppMappingRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkAppDashboardResponse;
+import org.apache.streampark.console.core.response.flink.FlinkAppResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Converts between Flink application entities and API request/response contracts.
+ */
+public final class FlinkApplicationAssembler {
+
+    private FlinkApplicationAssembler() {
+    }
+
+    public static FlinkApplication toEntity(FlinkAppCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        BeanUtils.copyProperties(request, app);
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = toEntity((FlinkAppCreateRequest) request);
+        app.setId(request.getId());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppStartRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setRestoreOrTriggerSavepoint(request.getRestoreOrTriggerSavepoint());
+        app.setSavepointPath(request.getSavepointPath());
+        app.setAllowNonRestored(request.getAllowNonRestored());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppCancelRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setRestoreOrTriggerSavepoint(request.getRestoreOrTriggerSavepoint());
+        app.setDrain(request.getDrain());
+        app.setNativeFormat(request.getNativeFormat());
+        app.setSavepointPath(request.getSavepointPath());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppCopyRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setJobName(request.getJobName());
+        app.setArgs(request.getArgs());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppMappingRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setClusterId(request.getClusterId());
+        app.setJobId(request.getJobId());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        BeanUtils.copyProperties(request, app);
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppCheckNameRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setJobName(request.getJobName());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppConfigRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setConfig(request.getConfig());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppCheckSavepointPathRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setSavepointPath(request.getSavepointPath());
+        return app;
+    }
+
+    public static FlinkApplication toEntity(FlinkAppGetMainRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplication app = new FlinkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setProjectId(request.getProjectId());
+        app.setJar(request.getJar());
+        app.setModule(request.getModule());
+        return app;
+    }
+
+    public static FlinkAppResponse toResponse(FlinkApplication app) {
+        if (app == null) {
+            return null;
+        }
+        FlinkAppResponse response = new FlinkAppResponse();
+        BeanUtils.copyProperties(app, response);
+        return response;
+    }
+
+    public static IPage<FlinkAppResponse> toPageResponse(IPage<FlinkApplication> page) {
+        if (page == null) {
+            return null;
+        }
+        Page<FlinkAppResponse> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+        List<FlinkAppResponse> records =
+            page.getRecords().stream().map(FlinkApplicationAssembler::toResponse).collect(Collectors.toList());
+        result.setRecords(records);
+        return result;
+    }
+
+    public static FlinkAppDashboardResponse toDashboardResponse(Map<String, Serializable> dashboardMap) {
+        if (dashboardMap == null) {
+            return null;
+        }
+        FlinkAppDashboardResponse response = new FlinkAppDashboardResponse();
+        response.setTask((JobsOverview.Task) dashboardMap.get("task"));
+        response.setJmMemory((Integer) dashboardMap.get("jmMemory"));
+        response.setTmMemory((Integer) dashboardMap.get("tmMemory"));
+        response.setTotalTM((Integer) dashboardMap.get("totalTM"));
+        response.setAvailableSlot((Integer) dashboardMap.get("availableSlot"));
+        response.setTotalSlot((Integer) dashboardMap.get("totalSlot"));
+        response.setRunningJob((Integer) dashboardMap.get("runningJob"));
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkClusterAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkClusterAssembler.java
new file mode 100644
index 0000000..cda0820
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkClusterAssembler.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.bean.ResponseResult;
+import org.apache.streampark.console.core.entity.FlinkCluster;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterCheckRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterPageQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkClusterCheckResponse;
+import org.apache.streampark.console.core.response.flink.FlinkClusterResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Converts between Flink cluster entities and API request/response contracts.
+ */
+public final class FlinkClusterAssembler {
+
+    private FlinkClusterAssembler() {
+    }
+
+    public static FlinkCluster toEntity(FlinkClusterCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkCluster cluster = new FlinkCluster();
+        BeanUtils.copyProperties(request, cluster);
+        return cluster;
+    }
+
+    public static FlinkCluster toEntity(FlinkClusterUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkCluster cluster = toEntity((FlinkClusterCreateRequest) request);
+        cluster.setId(request.getId());
+        return cluster;
+    }
+
+    public static FlinkCluster toEntity(FlinkClusterCheckRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkCluster cluster = toEntity((FlinkClusterCreateRequest) request);
+        cluster.setId(request.getId());
+        return cluster;
+    }
+
+    public static FlinkCluster toEntity(FlinkClusterPageQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkCluster cluster = new FlinkCluster();
+        cluster.setClusterName(request.getClusterName());
+        return cluster;
+    }
+
+    public static FlinkCluster toEntity(IdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkCluster cluster = new FlinkCluster();
+        cluster.setId(request.getId());
+        return cluster;
+    }
+
+    public static FlinkClusterResponse toResponse(FlinkCluster cluster) {
+        if (cluster == null) {
+            return null;
+        }
+        FlinkClusterResponse response = new FlinkClusterResponse();
+        BeanUtils.copyProperties(cluster, response);
+        return response;
+    }
+
+    public static List<FlinkClusterResponse> toListResponse(List<FlinkCluster> clusters) {
+        if (clusters == null) {
+            return Collections.emptyList();
+        }
+        return clusters.stream().map(FlinkClusterAssembler::toResponse).collect(Collectors.toList());
+    }
+
+    public static IPage<FlinkClusterResponse> toPageResponse(IPage<FlinkCluster> page) {
+        return DtoAssembler.toPage(page, FlinkClusterAssembler::toResponse);
+    }
+
+    public static FlinkClusterCheckResponse toCheckResponse(ResponseResult<?> checkResult) {
+        if (checkResult == null) {
+            return null;
+        }
+        FlinkClusterCheckResponse response = new FlinkClusterCheckResponse();
+        response.setStatus(checkResult.getStatus());
+        response.setMsg(checkResult.getMsg());
+        response.setResult((Serializable) checkResult.getResult());
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkConfAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkConfAssembler.java
new file mode 100644
index 0000000..fc14a74
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkConfAssembler.java
@@ -0,0 +1,94 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkApplicationConfig;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkConfListQueryRequest;
+import org.apache.streampark.console.core.response.flink.FlinkConfHadoopResponse;
+import org.apache.streampark.console.core.response.flink.FlinkConfResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Converts between Flink application config entities and API request/response contracts.
+ */
+public final class FlinkConfAssembler {
+
+    private FlinkConfAssembler() {
+    }
+
+    public static FlinkApplicationConfig toEntity(FlinkConfListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplicationConfig config = new FlinkApplicationConfig();
+        config.setAppId(request.getAppId());
+        return config;
+    }
+
+    public static FlinkApplicationConfig toEntity(IdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkApplicationConfig config = new FlinkApplicationConfig();
+        config.setId(request.getId());
+        return config;
+    }
+
+    public static Long toAppId(FlinkAppIdRequest request) {
+        return request == null ? null : request.getId();
+    }
+
+    public static FlinkConfResponse toResponse(FlinkApplicationConfig config) {
+        if (config == null) {
+            return null;
+        }
+        FlinkConfResponse response = new FlinkConfResponse();
+        BeanUtils.copyProperties(config, response);
+        return response;
+    }
+
+    public static List<FlinkConfResponse> toListResponse(List<FlinkApplicationConfig> configs) {
+        if (configs == null) {
+            return Collections.emptyList();
+        }
+        return configs.stream().map(FlinkConfAssembler::toResponse).collect(Collectors.toList());
+    }
+
+    public static IPage<FlinkConfResponse> toPageResponse(IPage<FlinkApplicationConfig> page) {
+        return DtoAssembler.toPage(page, FlinkConfAssembler::toResponse);
+    }
+
+    public static FlinkConfHadoopResponse toHadoopResponse(Map<String, Map<String, String>> hadoopConf) {
+        if (hadoopConf == null) {
+            return null;
+        }
+        FlinkConfHadoopResponse response = new FlinkConfHadoopResponse();
+        response.setHadoop(hadoopConf.get("hadoop"));
+        response.setHive(hadoopConf.get("hive"));
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkEnvAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkEnvAssembler.java
new file mode 100644
index 0000000..79b16f3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkEnvAssembler.java
@@ -0,0 +1,109 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkEnv;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvCheckRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvPageQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkEnvResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Converts between Flink environment entities and API request/response contracts.
+ */
+public final class FlinkEnvAssembler {
+
+    private FlinkEnvAssembler() {
+    }
+
+    public static FlinkEnv toEntity(FlinkEnvCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkEnv env = new FlinkEnv();
+        BeanUtils.copyProperties(request, env);
+        return env;
+    }
+
+    public static FlinkEnv toEntity(FlinkEnvUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkEnv env = toEntity((FlinkEnvCreateRequest) request);
+        env.setId(request.getId());
+        return env;
+    }
+
+    public static FlinkEnv toEntity(FlinkEnvCheckRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkEnv env = new FlinkEnv();
+        env.setId(request.getId());
+        env.setFlinkName(request.getFlinkName());
+        env.setFlinkHome(request.getFlinkHome());
+        return env;
+    }
+
+    public static FlinkEnv toEntity(FlinkEnvPageQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkEnv env = new FlinkEnv();
+        env.setFlinkName(request.getFlinkName());
+        return env;
+    }
+
+    public static FlinkEnv toEntity(IdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkEnv env = new FlinkEnv();
+        env.setId(request.getId());
+        return env;
+    }
+
+    public static FlinkEnvResponse toResponse(FlinkEnv env) {
+        if (env == null) {
+            return null;
+        }
+        FlinkEnvResponse response = new FlinkEnvResponse();
+        BeanUtils.copyProperties(env, response);
+        return response;
+    }
+
+    public static List<FlinkEnvResponse> toListResponse(List<FlinkEnv> envs) {
+        if (envs == null) {
+            return Collections.emptyList();
+        }
+        return envs.stream().map(FlinkEnvAssembler::toResponse).collect(Collectors.toList());
+    }
+
+    public static IPage<FlinkEnvResponse> toPageResponse(IPage<FlinkEnv> page) {
+        return DtoAssembler.toPage(page, FlinkEnvAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkPipelineAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkPipelineAssembler.java
new file mode 100644
index 0000000..c3b648b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkPipelineAssembler.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.bean.AppBuildDockerResolvedDetail;
+import org.apache.streampark.console.core.entity.ApplicationBuildPipeline;
+import org.apache.streampark.console.core.response.flink.FlinkPipelineDetailResponse;
+
+/**
+ * Converts between Flink build pipeline data and API response contracts.
+ */
+public final class FlinkPipelineAssembler {
+
+    private FlinkPipelineAssembler() {
+    }
+
+    public static FlinkPipelineDetailResponse toDetailResponse(
+                                                               ApplicationBuildPipeline.View pipeline,
+                                                               AppBuildDockerResolvedDetail docker) {
+        FlinkPipelineDetailResponse response = new FlinkPipelineDetailResponse();
+        response.setPipeline(pipeline);
+        response.setDocker(docker);
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkSqlAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkSqlAssembler.java
new file mode 100644
index 0000000..94ffdff
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/FlinkSqlAssembler.java
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkSql;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlDeleteRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlListQueryRequest;
+import org.apache.streampark.console.core.response.flink.FlinkSqlResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Converts between Flink SQL entities and API request/response contracts.
+ */
+public final class FlinkSqlAssembler {
+
+    private FlinkSqlAssembler() {
+    }
+
+    public static FlinkSql toQueryEntity(FlinkSqlListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkSql flinkSql = new FlinkSql();
+        flinkSql.setAppId(request.getAppId());
+        flinkSql.setTeamId(request.getTeamId());
+        return flinkSql;
+    }
+
+    public static FlinkSql toEntity(FlinkSqlDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkSql flinkSql = new FlinkSql();
+        flinkSql.setAppId(request.getAppId());
+        flinkSql.setTeamId(request.getTeamId());
+        flinkSql.setId(request.getId());
+        return flinkSql;
+    }
+
+    public static Long toAppId(FlinkAppIdRequest request) {
+        return request == null ? null : request.getId();
+    }
+
+    public static FlinkSqlResponse toResponse(FlinkSql flinkSql) {
+        if (flinkSql == null) {
+            return null;
+        }
+        FlinkSqlResponse response = new FlinkSqlResponse();
+        BeanUtils.copyProperties(flinkSql, response);
+        return response;
+    }
+
+    public static FlinkSqlResponse[] toArrayResponse(FlinkSql[] flinkSqls) {
+        if (flinkSqls == null) {
+            return new FlinkSqlResponse[0];
+        }
+        FlinkSqlResponse[] responses = new FlinkSqlResponse[flinkSqls.length];
+        for (int i = 0; i < flinkSqls.length; i++) {
+            responses[i] = toResponse(flinkSqls[i]);
+        }
+        return responses;
+    }
+
+    public static List<FlinkSqlResponse> toListResponse(List<FlinkSql> flinkSqls) {
+        if (flinkSqls == null) {
+            return Collections.emptyList();
+        }
+        return flinkSqls.stream().map(FlinkSqlAssembler::toResponse).collect(Collectors.toList());
+    }
+
+    public static IPage<FlinkSqlResponse> toPageResponse(IPage<FlinkSql> page) {
+        return DtoAssembler.toPage(page, FlinkSqlAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/MessageAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/MessageAssembler.java
new file mode 100644
index 0000000..4292961
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/MessageAssembler.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.Message;
+import org.apache.streampark.console.core.response.message.MessageResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/** Converts between message entities and API response contracts. */
+public final class MessageAssembler {
+
+    private MessageAssembler() {
+    }
+
+    public static MessageResponse toResponse(Message message) {
+        return DtoAssembler.toDto(message, MessageResponse.class);
+    }
+
+    public static IPage<MessageResponse> toPageResponse(IPage<Message> page) {
+        return DtoAssembler.toPage(page, MessageAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ProjectAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ProjectAssembler.java
new file mode 100644
index 0000000..326229a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ProjectAssembler.java
@@ -0,0 +1,129 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.Project;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.project.ProjectBuildLogRequest;
+import org.apache.streampark.console.core.request.project.ProjectCreateRequest;
+import org.apache.streampark.console.core.request.project.ProjectExistsRequest;
+import org.apache.streampark.console.core.request.project.ProjectGitRequest;
+import org.apache.streampark.console.core.request.project.ProjectListQueryRequest;
+import org.apache.streampark.console.core.request.project.ProjectModuleRequest;
+import org.apache.streampark.console.core.request.project.ProjectUpdateRequest;
+import org.apache.streampark.console.core.response.project.ProjectBranchesResponse;
+import org.apache.streampark.console.core.response.project.ProjectResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+
+/** Converts between project entities and API request/response contracts. */
+public final class ProjectAssembler {
+
+    private ProjectAssembler() {
+    }
+
+    public static Project toEntity(ProjectCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = new Project();
+        BeanUtils.copyProperties(request, project);
+        return project;
+    }
+
+    public static Project toEntity(ProjectUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = toEntity((ProjectCreateRequest) request);
+        project.setId(request.getId());
+        return project;
+    }
+
+    public static Project toEntity(ProjectListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = new Project();
+        BeanUtils.copyProperties(request, project);
+        return project;
+    }
+
+    public static Project toEntity(TeamScopedIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = new Project();
+        project.setId(request.getId());
+        project.setTeamId(request.getTeamId());
+        return project;
+    }
+
+    public static Project toEntity(ProjectGitRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = toEntity((TeamScopedIdRequest) request);
+        BeanUtils.copyProperties(request, project, "id", "teamId");
+        return project;
+    }
+
+    public static Project toEntity(ProjectModuleRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = toEntity((TeamScopedIdRequest) request);
+        project.setModule(request.getModule());
+        return project;
+    }
+
+    public static Project toEntity(ProjectExistsRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Project project = toEntity((TeamScopedIdRequest) request);
+        project.setName(request.getName());
+        return project;
+    }
+
+    public static Project toEntity(ProjectBuildLogRequest request) {
+        return toEntity((TeamScopedIdRequest) request);
+    }
+
+    public static ProjectResponse toResponse(Project project) {
+        return DtoAssembler.toDto(project, ProjectResponse.class);
+    }
+
+    public static IPage<ProjectResponse> toPageResponse(IPage<Project> page) {
+        return DtoAssembler.toPage(page, ProjectAssembler::toResponse);
+    }
+
+    public static List<ProjectResponse> toListResponse(List<Project> projects) {
+        return DtoAssembler.toList(projects, ProjectAssembler::toResponse);
+    }
+
+    public static ProjectBranchesResponse toBranchesResponse(List<String> branches, List<String> tags) {
+        ProjectBranchesResponse response = new ProjectBranchesResponse();
+        response.setBranches(branches);
+        response.setTags(tags);
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ResourceAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ResourceAssembler.java
new file mode 100644
index 0000000..eaac455
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/ResourceAssembler.java
@@ -0,0 +1,146 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.bean.UploadResponse;
+import org.apache.streampark.console.core.entity.Resource;
+import org.apache.streampark.console.core.enums.EngineTypeEnum;
+import org.apache.streampark.console.core.enums.ResourceTypeEnum;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.resource.ResourceCreateRequest;
+import org.apache.streampark.console.core.request.resource.ResourcePageQueryRequest;
+import org.apache.streampark.console.core.request.resource.ResourceUpdateRequest;
+import org.apache.streampark.console.core.response.resource.ResourceCheckResponse;
+import org.apache.streampark.console.core.response.resource.ResourceResponse;
+import org.apache.streampark.console.core.response.resource.ResourceUploadResponse;
+import org.apache.streampark.console.core.service.result.ResourceCheckResult;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+
+/** Converts between resource entities and API request/response contracts. */
+public final class ResourceAssembler {
+
+    private ResourceAssembler() {
+    }
+
+    public static Resource toEntity(ResourceCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Resource resource = new Resource();
+        BeanUtils.copyProperties(request, resource, "resourceType", "engineType", "resourcePath");
+        resource.setResourceType(parseResourceType(request.getResourceType()));
+        resource.setEngineType(parseEngineType(request.getEngineType()));
+        return resource;
+    }
+
+    public static Resource toEntity(ResourceUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Resource resource = toEntity((ResourceCreateRequest) request);
+        resource.setId(request.getId());
+        return resource;
+    }
+
+    public static Resource toEntity(ResourcePageQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Resource resource = new Resource();
+        resource.setTeamId(request.getTeamId());
+        resource.setResourceName(request.getResourceName());
+        resource.setResourceType(parseResourceType(request.getResourceType()));
+        resource.setEngineType(parseEngineType(request.getEngineType()));
+        return resource;
+    }
+
+    public static Resource toEntity(TeamScopedIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Resource resource = new Resource();
+        resource.setId(request.getId());
+        resource.setTeamId(request.getTeamId());
+        return resource;
+    }
+
+    public static ResourceResponse toResponse(Resource resource) {
+        if (resource == null) {
+            return null;
+        }
+        ResourceResponse response = DtoAssembler.toDto(resource, ResourceResponse.class);
+        if (resource.getResourceType() != null) {
+            response.setResourceType(resource.getResourceType().name());
+        }
+        if (resource.getEngineType() != null) {
+            response.setEngineType(resource.getEngineType().name());
+        }
+        return response;
+    }
+
+    public static IPage<ResourceResponse> toPageResponse(IPage<Resource> page) {
+        return DtoAssembler.toPage(page, ResourceAssembler::toResponse);
+    }
+
+    public static List<ResourceResponse> toListResponse(List<Resource> resources) {
+        return DtoAssembler.toList(resources, ResourceAssembler::toResponse);
+    }
+
+    public static ResourceUploadResponse toUploadResponse(UploadResponse upload) {
+        return DtoAssembler.toDto(upload, ResourceUploadResponse.class);
+    }
+
+    public static ResourceCheckResponse toCheckResponse(ResourceCheckResult result) {
+        if (result == null) {
+            return null;
+        }
+        ResourceCheckResponse response = new ResourceCheckResponse();
+        response.setState(result.getState());
+        response.setException(result.getException());
+        response.setConnector(result.getConnector());
+        return response;
+    }
+
+    private static ResourceTypeEnum parseResourceType(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        try {
+            return ResourceTypeEnum.valueOf(value);
+        } catch (IllegalArgumentException ignored) {
+            return ResourceTypeEnum.of(Integer.valueOf(value));
+        }
+    }
+
+    private static EngineTypeEnum parseEngineType(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        try {
+            return EngineTypeEnum.valueOf(value);
+        } catch (IllegalArgumentException ignored) {
+            return EngineTypeEnum.of(Integer.valueOf(value));
+        }
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SavepointAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SavepointAssembler.java
new file mode 100644
index 0000000..fff37af
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SavepointAssembler.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkSavepoint;
+import org.apache.streampark.console.core.request.flink.SavepointDeleteRequest;
+import org.apache.streampark.console.core.request.flink.SavepointHistoryQueryRequest;
+import org.apache.streampark.console.core.response.flink.SavepointResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+/**
+ * Converts between Flink savepoint entities and API request/response contracts.
+ */
+public final class SavepointAssembler {
+
+    private SavepointAssembler() {
+    }
+
+    public static FlinkSavepoint toEntity(SavepointHistoryQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkSavepoint savepoint = new FlinkSavepoint();
+        savepoint.setAppId(request.getAppId());
+        savepoint.setTeamId(request.getTeamId());
+        return savepoint;
+    }
+
+    public static FlinkSavepoint toEntity(SavepointDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        FlinkSavepoint savepoint = new FlinkSavepoint();
+        savepoint.setAppId(request.getAppId());
+        savepoint.setTeamId(request.getTeamId());
+        savepoint.setId(request.getId());
+        return savepoint;
+    }
+
+    public static SavepointResponse toResponse(FlinkSavepoint savepoint) {
+        if (savepoint == null) {
+            return null;
+        }
+        SavepointResponse response = new SavepointResponse();
+        BeanUtils.copyProperties(savepoint, response);
+        return response;
+    }
+
+    public static IPage<SavepointResponse> toPageResponse(IPage<FlinkSavepoint> page) {
+        return DtoAssembler.toPage(page, SavepointAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SettingAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SettingAssembler.java
new file mode 100644
index 0000000..682aca1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SettingAssembler.java
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.bean.DockerConfig;
+import org.apache.streampark.console.core.bean.ResponseResult;
+import org.apache.streampark.console.core.bean.SenderEmail;
+import org.apache.streampark.console.core.entity.Setting;
+import org.apache.streampark.console.core.request.setting.SettingDockerRequest;
+import org.apache.streampark.console.core.request.setting.SettingEmailRequest;
+import org.apache.streampark.console.core.request.setting.SettingUpdateRequest;
+import org.apache.streampark.console.core.response.setting.SettingCheckResponse;
+import org.apache.streampark.console.core.response.setting.SettingDockerResponse;
+import org.apache.streampark.console.core.response.setting.SettingEmailResponse;
+import org.apache.streampark.console.core.response.setting.SettingResponse;
+
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serializable;
+import java.util.List;
+
+/** Converts between setting entities/beans and API request/response contracts. */
+public final class SettingAssembler {
+
+    private SettingAssembler() {
+    }
+
+    public static Setting toEntity(SettingUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Setting setting = new Setting();
+        BeanUtils.copyProperties(request, setting);
+        return setting;
+    }
+
+    public static DockerConfig toDockerConfig(SettingDockerRequest request) {
+        return DtoAssembler.toDto(request, DockerConfig.class);
+    }
+
+    public static SenderEmail toSenderEmail(SettingEmailRequest request) {
+        return DtoAssembler.toDto(request, SenderEmail.class);
+    }
+
+    public static SettingResponse toResponse(Setting setting) {
+        return DtoAssembler.toDto(setting, SettingResponse.class);
+    }
+
+    public static List<SettingResponse> toListResponse(List<Setting> settings) {
+        return DtoAssembler.toList(settings, SettingAssembler::toResponse);
+    }
+
+    public static SettingDockerResponse toDockerResponse(DockerConfig dockerConfig) {
+        return DtoAssembler.toDto(dockerConfig, SettingDockerResponse.class);
+    }
+
+    public static SettingEmailResponse toEmailResponse(SenderEmail senderEmail) {
+        return DtoAssembler.toDto(senderEmail, SettingEmailResponse.class);
+    }
+
+    public static SettingCheckResponse toCheckResponse(ResponseResult<?> result) {
+        if (result == null) {
+            return null;
+        }
+        SettingCheckResponse response = new SettingCheckResponse();
+        response.setStatus(result.getStatus());
+        response.setMsg(result.getMsg());
+        response.setResult((Serializable) result.getResult());
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkApplicationAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkApplicationAssembler.java
new file mode 100644
index 0000000..45d414b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkApplicationAssembler.java
@@ -0,0 +1,182 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.SparkApplication;
+import org.apache.streampark.console.core.enums.ReleaseStateEnum;
+import org.apache.streampark.console.core.request.spark.SparkAppCancelRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCheckNameRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppConfigRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCopyRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCreateRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppIdRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppListQueryRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppMappingRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppStartRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppUpdateRequest;
+import org.apache.streampark.console.core.response.spark.SparkAppDashboardResponse;
+import org.apache.streampark.console.core.response.spark.SparkAppResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Converts between Spark application entities and API request/response contracts.
+ */
+public final class SparkApplicationAssembler {
+
+    private SparkApplicationAssembler() {
+    }
+
+    public static SparkApplication toEntity(SparkAppCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        BeanUtils.copyProperties(request, app);
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = toEntity((SparkAppCreateRequest) request);
+        app.setId(request.getId());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppStartRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppCancelRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppCopyRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setAppName(request.getAppName());
+        app.setAppArgs(request.getAppArgs());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppMappingRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setClusterId(request.getClusterId());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        BeanUtils.copyProperties(request, app);
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppCheckNameRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setAppName(request.getAppName());
+        return app;
+    }
+
+    public static SparkApplication toEntity(SparkAppConfigRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setTeamId(request.getTeamId());
+        app.setConfig(request.getConfig());
+        return app;
+    }
+
+    public static SparkApplication toCleanEntity(SparkAppIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkApplication app = new SparkApplication();
+        app.setId(request.getId());
+        app.setRelease(ReleaseStateEnum.DONE.get());
+        return app;
+    }
+
+    public static SparkAppResponse toResponse(SparkApplication app) {
+        return DtoAssembler.toDto(app, SparkAppResponse.class);
+    }
+
+    public static IPage<SparkAppResponse> toPageResponse(IPage<SparkApplication> page) {
+        return DtoAssembler.toPage(page, SparkApplicationAssembler::toResponse);
+    }
+
+    public static SparkAppDashboardResponse toDashboardResponse(Map<String, Serializable> dashboardMap) {
+        if (dashboardMap == null) {
+            return null;
+        }
+        SparkAppDashboardResponse response = new SparkAppDashboardResponse();
+        response.setRunningApplication((Integer) dashboardMap.get("runningApplication"));
+        response.setNumTasks((Long) dashboardMap.get("numTasks"));
+        response.setNumCompletedTasks((Long) dashboardMap.get("numCompletedTasks"));
+        response.setNumStages((Long) dashboardMap.get("numStages"));
+        response.setNumCompletedStages((Long) dashboardMap.get("numCompletedStages"));
+        response.setUsedMemory((Long) dashboardMap.get("usedMemory"));
+        response.setUsedVCores((Long) dashboardMap.get("usedVCores"));
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkConfigAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkConfigAssembler.java
new file mode 100644
index 0000000..b7a12d0
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkConfigAssembler.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.SparkApplicationConfig;
+import org.apache.streampark.console.core.request.spark.SparkConfListQueryRequest;
+import org.apache.streampark.console.core.response.spark.SparkConfResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.util.List;
+
+/**
+ * Converts between Spark application config entities and API request/response contracts.
+ */
+public final class SparkConfigAssembler {
+
+    private SparkConfigAssembler() {
+    }
+
+    public static SparkApplicationConfig toEntity(SparkConfListQueryRequest request) {
+        return DtoAssembler.toDto(request, SparkApplicationConfig.class);
+    }
+
+    public static SparkConfResponse toResponse(SparkApplicationConfig config) {
+        if (config == null) {
+            return null;
+        }
+        SparkConfResponse response = DtoAssembler.toDto(config, SparkConfResponse.class);
+        response.setEffective(config.isEffective());
+        return response;
+    }
+
+    public static IPage<SparkConfResponse> toPageResponse(IPage<SparkApplicationConfig> page) {
+        return DtoAssembler.toPage(page, SparkConfigAssembler::toResponse);
+    }
+
+    public static List<SparkConfResponse> toListResponse(List<SparkApplicationConfig> configs) {
+        return DtoAssembler.toList(configs, SparkConfigAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkEnvAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkEnvAssembler.java
new file mode 100644
index 0000000..f0d0a29
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkEnvAssembler.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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.SparkEnv;
+import org.apache.streampark.console.core.request.spark.SparkEnvCheckRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvCreateRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvUpdateRequest;
+import org.apache.streampark.console.core.response.spark.SparkEnvResponse;
+
+import java.util.List;
+
+/**
+ * Converts between Spark environment entities and API request/response contracts.
+ */
+public final class SparkEnvAssembler {
+
+    private SparkEnvAssembler() {
+    }
+
+    public static SparkEnv toEntity(SparkEnvCreateRequest request) {
+        return DtoAssembler.toDto(request, SparkEnv.class);
+    }
+
+    public static SparkEnv toEntity(SparkEnvUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkEnv env = toEntity((SparkEnvCreateRequest) request);
+        env.setId(request.getId());
+        return env;
+    }
+
+    public static SparkEnv toEntity(SparkEnvCheckRequest request) {
+        return DtoAssembler.toDto(request, SparkEnv.class);
+    }
+
+    public static SparkEnvResponse toResponse(SparkEnv env) {
+        return DtoAssembler.toDto(env, SparkEnvResponse.class);
+    }
+
+    public static List<SparkEnvResponse> toListResponse(List<SparkEnv> envs) {
+        return DtoAssembler.toList(envs, SparkEnvAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkPipelineAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkPipelineAssembler.java
new file mode 100644
index 0000000..9fb0435
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkPipelineAssembler.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.response.spark.SparkPipelineDetailResponse;
+
+/**
+ * Converts Spark build pipeline data to API response contracts.
+ */
+public final class SparkPipelineAssembler {
+
+    private SparkPipelineAssembler() {
+    }
+
+    public static SparkPipelineDetailResponse toDetailResponse(Object pipelineView) {
+        SparkPipelineDetailResponse response = new SparkPipelineDetailResponse();
+        response.setPipeline(pipelineView);
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkSqlAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkSqlAssembler.java
new file mode 100644
index 0000000..63c2ed4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/SparkSqlAssembler.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.SparkSql;
+import org.apache.streampark.console.core.request.spark.SparkSqlDeleteRequest;
+import org.apache.streampark.console.core.response.spark.SparkSqlResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.util.List;
+
+/**
+ * Converts between Spark SQL entities and API request/response contracts.
+ */
+public final class SparkSqlAssembler {
+
+    private SparkSqlAssembler() {
+    }
+
+    public static SparkSql toDeleteEntity(SparkSqlDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        SparkSql sparkSql = new SparkSql();
+        sparkSql.setAppId(request.getAppId());
+        sparkSql.setSql(request.getSql());
+        return sparkSql;
+    }
+
+    public static SparkSqlResponse toResponse(SparkSql sparkSql) {
+        if (sparkSql == null) {
+            return null;
+        }
+        SparkSqlResponse response = DtoAssembler.toDto(sparkSql, SparkSqlResponse.class);
+        response.setEffective(sparkSql.isEffective());
+        response.setSqlDifference(sparkSql.isSqlDifference());
+        response.setDependencyDifference(sparkSql.isDependencyDifference());
+        return response;
+    }
+
+    public static SparkSqlResponse[] toResponseArray(SparkSql[] sparkSqls) {
+        if (sparkSqls == null) {
+            return new SparkSqlResponse[0];
+        }
+        SparkSqlResponse[] responses = new SparkSqlResponse[sparkSqls.length];
+        for (int i = 0; i < sparkSqls.length; i++) {
+            responses[i] = toResponse(sparkSqls[i]);
+        }
+        return responses;
+    }
+
+    public static IPage<SparkSqlResponse> toPageResponse(IPage<SparkSql> page) {
+        return DtoAssembler.toPage(page, SparkSqlAssembler::toResponse);
+    }
+
+    public static List<SparkSqlResponse> toListResponse(List<SparkSql> sqlList) {
+        return DtoAssembler.toList(sqlList, SparkSqlAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/VariableAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/VariableAssembler.java
new file mode 100644
index 0000000..ca98795
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/VariableAssembler.java
@@ -0,0 +1,87 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.Variable;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.variable.VariableCreateRequest;
+import org.apache.streampark.console.core.request.variable.VariablePageQueryRequest;
+import org.apache.streampark.console.core.request.variable.VariableUpdateRequest;
+import org.apache.streampark.console.core.response.variable.VariableResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+
+/** Converts between variable entities and API request/response contracts. */
+public final class VariableAssembler {
+
+    private VariableAssembler() {
+    }
+
+    public static Variable toEntity(VariableCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Variable variable = new Variable();
+        BeanUtils.copyProperties(request, variable);
+        return variable;
+    }
+
+    public static Variable toEntity(VariableUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Variable variable = toEntity((VariableCreateRequest) request);
+        variable.setId(request.getId());
+        return variable;
+    }
+
+    public static Variable toEntity(VariablePageQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Variable variable = new Variable();
+        variable.setTeamId(request.getTeamId());
+        variable.setVariableCode(request.getVariableCode());
+        return variable;
+    }
+
+    public static Variable toEntity(TeamScopedIdRequest request) {
+        if (request == null) {
+            return null;
+        }
+        Variable variable = new Variable();
+        variable.setId(request.getId());
+        variable.setTeamId(request.getTeamId());
+        return variable;
+    }
+
+    public static VariableResponse toResponse(Variable variable) {
+        return DtoAssembler.toDto(variable, VariableResponse.class);
+    }
+
+    public static IPage<VariableResponse> toPageResponse(IPage<Variable> page) {
+        return DtoAssembler.toPage(page, VariableAssembler::toResponse);
+    }
+
+    public static List<VariableResponse> toListResponse(List<Variable> variables) {
+        return DtoAssembler.toList(variables, VariableAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/YarnQueueAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/YarnQueueAssembler.java
new file mode 100644
index 0000000..3612f93
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/assembler/YarnQueueAssembler.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.bean.ResponseResult;
+import org.apache.streampark.console.core.entity.YarnQueue;
+import org.apache.streampark.console.core.request.yarn.YarnQueueCreateRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueDeleteRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueListQueryRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueUpdateRequest;
+import org.apache.streampark.console.core.response.yarn.YarnQueueCheckResponse;
+import org.apache.streampark.console.core.response.yarn.YarnQueueResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+
+/** Converts between yarn queue entities and API request/response contracts. */
+public final class YarnQueueAssembler {
+
+    private YarnQueueAssembler() {
+    }
+
+    public static YarnQueue toEntity(YarnQueueCreateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        YarnQueue yarnQueue = new YarnQueue();
+        BeanUtils.copyProperties(request, yarnQueue);
+        return yarnQueue;
+    }
+
+    public static YarnQueue toEntity(YarnQueueUpdateRequest request) {
+        if (request == null) {
+            return null;
+        }
+        YarnQueue yarnQueue = toEntity((YarnQueueCreateRequest) request);
+        yarnQueue.setId(request.getId());
+        return yarnQueue;
+    }
+
+    public static YarnQueue toEntity(YarnQueueListQueryRequest request) {
+        if (request == null) {
+            return null;
+        }
+        YarnQueue yarnQueue = new YarnQueue();
+        BeanUtils.copyProperties(request, yarnQueue);
+        return yarnQueue;
+    }
+
+    public static YarnQueue toEntity(YarnQueueDeleteRequest request) {
+        if (request == null) {
+            return null;
+        }
+        YarnQueue yarnQueue = new YarnQueue();
+        yarnQueue.setId(request.getId());
+        yarnQueue.setTeamId(request.getTeamId());
+        return yarnQueue;
+    }
+
+    public static YarnQueueResponse toResponse(YarnQueue yarnQueue) {
+        return DtoAssembler.toDto(yarnQueue, YarnQueueResponse.class);
+    }
+
+    public static IPage<YarnQueueResponse> toPageResponse(IPage<YarnQueue> page) {
+        return DtoAssembler.toPage(page, YarnQueueAssembler::toResponse);
+    }
+
+    public static YarnQueueCheckResponse toCheckResponse(ResponseResult<String> checkResult) {
+        if (checkResult == null) {
+            return null;
+        }
+        YarnQueueCheckResponse response = new YarnQueueCheckResponse();
+        response.setStatus(checkResult.getStatus());
+        response.setMsg(checkResult.getMsg());
+        response.setResult(checkResult.getResult());
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/AlertConfigParams.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/AlertConfigParams.java
deleted file mode 100644
index 0b34f56..0000000
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/AlertConfigParams.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 org.apache.streampark.console.core.bean;
-
-import org.apache.streampark.console.base.util.JacksonUtils;
-import org.apache.streampark.console.core.entity.AlertConfig;
-
-import org.apache.commons.lang3.StringUtils;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-
-import java.io.Serializable;
-
-@Getter
-@Setter
-@Slf4j
-public class AlertConfigParams implements Serializable {
-
-    private Long id;
-
-    private Long userId;
-
-    private String alertName;
-
-    private Integer alertType;
-
-    private AlertEmailParams emailParams;
-
-    private AlertDingTalkParams dingTalkParams;
-
-    private AlertWeComParams weComParams;
-
-    private AlertHttpCallbackParams httpCallbackParams;
-
-    private AlertLarkParams larkParams;
-
-    public static AlertConfigParams of(AlertConfig config) {
-        if (config == null) {
-            return null;
-        }
-        AlertConfigParams params = new AlertConfigParams();
-        BeanUtils.copyProperties(
-            config,
-            params,
-            "emailParams",
-            "dingTalkParams",
-            "weComParams",
-            "httpCallbackParams",
-            "larkParams");
-        try {
-            if (StringUtils.isNotBlank(config.getEmailParams())) {
-                params.setEmailParams(JacksonUtils.read(config.getEmailParams(), AlertEmailParams.class));
-            }
-            if (StringUtils.isNotBlank(config.getDingTalkParams())) {
-                params.setDingTalkParams(
-                    JacksonUtils.read(config.getDingTalkParams(), AlertDingTalkParams.class));
-            }
-            if (StringUtils.isNotBlank(config.getWeComParams())) {
-                params.setWeComParams(JacksonUtils.read(config.getWeComParams(), AlertWeComParams.class));
-            }
-            if (StringUtils.isNotBlank(config.getHttpCallbackParams())) {
-                params.setHttpCallbackParams(
-                    JacksonUtils.read(config.getHttpCallbackParams(), AlertHttpCallbackParams.class));
-            }
-            if (StringUtils.isNotBlank(config.getLarkParams())) {
-                params.setLarkParams(JacksonUtils.read(config.getLarkParams(), AlertLarkParams.class));
-            }
-        } catch (JsonProcessingException e) {
-            log.error("Json read failed", e);
-        }
-        return params;
-    }
-}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/ApiContractDocument.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/ApiContractDocument.java
new file mode 100644
index 0000000..da6325e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/ApiContractDocument.java
@@ -0,0 +1,62 @@
+/*
+ * 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 org.apache.streampark.console.core.bean;
+
+import org.apache.streampark.console.core.bean.OpenAPISchema.Schema;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Exported HTTP contract snapshot for console REST endpoints. */
+@Getter
+@Setter
+public class ApiContractDocument implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<ApiEndpointDescriptor> endpoints = new ArrayList<>();
+
+    private Map<String, List<Schema>> dtoSchemas = new LinkedHashMap<>();
+
+    @Getter
+    @Setter
+    public static class ApiEndpointDescriptor implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        private String controller;
+
+        private String handler;
+
+        private String path;
+
+        private String httpMethod;
+
+        private String requestType;
+
+        private String responseDataType;
+
+        private List<Schema> requestSchema = new ArrayList<>();
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
index d714ee4..5872f55 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/bean/OpenAPISchema.java
@@ -21,6 +21,7 @@
 import lombok.Getter;
 import lombok.Setter;
 
+import java.io.Serializable;
 import java.util.List;
 
 @Getter
@@ -37,7 +38,9 @@
 
     @Getter
     @Setter
-    public static class Schema {
+    public static class Schema implements Serializable {
+
+        private static final long serialVersionUID = 1L;
 
         private String name;
 
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiContractExportService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiContractExportService.java
new file mode 100644
index 0000000..10f4e20
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiContractExportService.java
@@ -0,0 +1,171 @@
+/*
+ * 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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.base.domain.RestRequest;
+import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.bean.ApiContractDocument;
+import org.apache.streampark.console.core.bean.ApiContractDocument.ApiEndpointDescriptor;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Scans registered MVC handlers and exports request/response DTO metadata. */
+@Component
+public class ApiContractExportService {
+
+    private static final String CONSOLE_PACKAGE = "org.apache.streampark.console";
+
+    private final RequestMappingHandlerMapping handlerMapping;
+
+    public ApiContractExportService(RequestMappingHandlerMapping handlerMapping) {
+        this.handlerMapping = handlerMapping;
+    }
+
+    public ApiContractDocument exportContracts() {
+        Map<String, String> typeNames = RequestDtoSchemaBuilder.defaultTypeNames();
+        ApiContractDocument document = new ApiContractDocument();
+        Map<String, List<OpenAPISchema.Schema>> dtoSchemas = new LinkedHashMap<>();
+        Set<Class<?>> dtoClasses = new LinkedHashSet<>();
+
+        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMapping.getHandlerMethods().entrySet()) {
+            HandlerMethod handlerMethod = entry.getValue();
+            if (!isConsoleHandler(handlerMethod)) {
+                continue;
+            }
+            ApiEndpointDescriptor endpoint = toDescriptor(entry.getKey(), handlerMethod, typeNames, dtoClasses);
+            document.getEndpoints().add(endpoint);
+        }
+
+        for (Class<?> dtoClass : dtoClasses) {
+            String key = dtoClass.getSimpleName();
+            if (key.endsWith("Request")) {
+                dtoSchemas.put(key, RequestDtoSchemaBuilder.build(dtoClass, null, typeNames));
+            } else if (key.endsWith("Response")) {
+                dtoSchemas.put(key, ResponseDtoSchemaBuilder.build(dtoClass, typeNames));
+            }
+        }
+        document.setDtoSchemas(dtoSchemas);
+        return document;
+    }
+
+    private ApiEndpointDescriptor toDescriptor(
+                                               RequestMappingInfo mappingInfo,
+                                               HandlerMethod handlerMethod,
+                                               Map<String, String> typeNames,
+                                               Set<Class<?>> dtoClasses) {
+        ApiEndpointDescriptor descriptor = new ApiEndpointDescriptor();
+        Method method = handlerMethod.getMethod();
+        descriptor.setController(handlerMethod.getBeanType().getSimpleName());
+        descriptor.setHandler(method.getName());
+        descriptor.setHttpMethod(resolveHttpMethod(mappingInfo));
+        descriptor.setPath(resolvePath(mappingInfo));
+
+        Class<?> requestType = resolveRequestType(method);
+        if (requestType != null) {
+            descriptor.setRequestType(requestType.getSimpleName());
+            descriptor.setRequestSchema(RequestDtoSchemaBuilder.build(requestType, null, typeNames));
+            dtoClasses.add(requestType);
+        }
+
+        Class<?> responseDataType = resolveResponseDataClass(method);
+        descriptor.setResponseDataType(
+            responseDataType != null ? responseDataType.getSimpleName() : "Object");
+        if (responseDataType != null && responseDataType.getSimpleName().endsWith("Response")) {
+            dtoClasses.add(responseDataType);
+        }
+        return descriptor;
+    }
+
+    private static boolean isConsoleHandler(HandlerMethod handlerMethod) {
+        return handlerMethod.getBeanType().getName().startsWith(CONSOLE_PACKAGE);
+    }
+
+    private static String resolveHttpMethod(RequestMappingInfo mappingInfo) {
+        if (mappingInfo.getMethodsCondition().getMethods().isEmpty()) {
+            return "POST";
+        }
+        return mappingInfo.getMethodsCondition().getMethods().iterator().next().name();
+    }
+
+    private static String resolvePath(RequestMappingInfo mappingInfo) {
+        Set<String> patterns = new LinkedHashSet<>();
+        if (mappingInfo.getPatternsCondition() != null) {
+            patterns.addAll(mappingInfo.getPatternsCondition().getPatterns());
+        }
+        if (patterns.isEmpty()) {
+            return "/";
+        }
+        return patterns.iterator().next();
+    }
+
+    private static Class<?> resolveRequestType(Method method) {
+        for (Parameter parameter : method.getParameters()) {
+            Class<?> type = parameter.getType();
+            if (isSkippableParameter(type)) {
+                continue;
+            }
+            return type;
+        }
+        return null;
+    }
+
+    private static boolean isSkippableParameter(Class<?> type) {
+        return type.isPrimitive()
+            || type == String.class
+            || RestRequest.class.isAssignableFrom(type)
+            || type.getName().startsWith("javax.servlet")
+            || type.getName().startsWith("org.springframework");
+    }
+
+    private static Class<?> resolveResponseDataClass(Method method) {
+        Type genericReturnType = method.getGenericReturnType();
+        if (genericReturnType instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
+            Type rawType = parameterizedType.getRawType();
+            if (rawType == RestResponseBody.class || rawType == RestResponse.class) {
+                return extractClassType(parameterizedType.getActualTypeArguments()[0]);
+            }
+        }
+        return null;
+    }
+
+    private static Class<?> extractClassType(Type type) {
+        if (type instanceof Class) {
+            return (Class<?>) type;
+        }
+        if (type instanceof ParameterizedType) {
+            return extractClassType(((ParameterizedType) type).getRawType());
+        }
+        return null;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiTypeScriptGenerator.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiTypeScriptGenerator.java
new file mode 100644
index 0000000..99ce2f9
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ApiTypeScriptGenerator.java
@@ -0,0 +1,105 @@
+/*
+ * 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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.core.bean.ApiContractDocument;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/** Generates TypeScript interfaces from exported API contract metadata. */
+public final class ApiTypeScriptGenerator {
+
+    private static final String TS_TYPE_NUMBER = "number";
+
+    private ApiTypeScriptGenerator() {
+    }
+
+    public static String generate(ApiContractDocument document) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("// Auto-generated from console API contract export. Do not edit manually.\n\n");
+        builder.append("export interface RestResponseBody<T> {\n");
+        builder.append("  status: 'success' | 'error';\n");
+        builder.append("  code: ").append(TS_TYPE_NUMBER).append(";\n");
+        builder.append("  message?: string;\n");
+        builder.append("  data?: T;\n");
+        builder.append("}\n\n");
+
+        if (document.getDtoSchemas() != null) {
+            for (Map.Entry<String, List<OpenAPISchema.Schema>> entry : document.getDtoSchemas().entrySet()) {
+                builder.append("export interface ").append(entry.getKey()).append(" {\n");
+                for (OpenAPISchema.Schema schema : entry.getValue()) {
+                    builder.append("  ").append(schema.getName()).append(toOptional(schema.isRequired()));
+                    builder.append(": ").append(toTsType(schema.getType())).append(";\n");
+                }
+                builder.append("}\n\n");
+            }
+        }
+
+        builder.append("export interface ApiEndpointDescriptor {\n");
+        builder.append("  controller: string;\n");
+        builder.append("  handler: string;\n");
+        builder.append("  path: string;\n");
+        builder.append("  httpMethod: string;\n");
+        builder.append("  requestType?: string;\n");
+        builder.append("  responseDataType?: string;\n");
+        builder.append("}\n\n");
+
+        builder.append("export const apiEndpoints: ApiEndpointDescriptor[] = [\n");
+        for (ApiContractDocument.ApiEndpointDescriptor endpoint : document.getEndpoints()) {
+            builder.append("  {");
+            builder.append(" controller: '").append(endpoint.getController()).append("',");
+            builder.append(" handler: '").append(endpoint.getHandler()).append("',");
+            builder.append(" path: '").append(endpoint.getPath()).append("',");
+            builder.append(" httpMethod: '").append(endpoint.getHttpMethod()).append("',");
+            builder.append(" requestType: '").append(StringUtils.defaultString(endpoint.getRequestType())).append("',");
+            builder.append(" responseDataType: '")
+                .append(StringUtils.defaultString(endpoint.getResponseDataType()))
+                .append("'");
+            builder.append(" },\n");
+        }
+        builder.append("];\n");
+        return builder.toString();
+    }
+
+    private static String toOptional(boolean required) {
+        return required ? "" : "?";
+    }
+
+    private static String toTsType(String openApiType) {
+        if (openApiType == null) {
+            return "unknown";
+        }
+        if (openApiType.startsWith("integer")) {
+            return TS_TYPE_NUMBER;
+        }
+        if (openApiType.startsWith("number")) {
+            return TS_TYPE_NUMBER;
+        }
+        if ("boolean".equals(openApiType)) {
+            return "boolean";
+        }
+        if (openApiType.startsWith("string")) {
+            return "string";
+        }
+        return "unknown";
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
index 75f43a7..3eaa797 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/OpenAPIComponent.java
@@ -40,6 +40,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -119,10 +120,8 @@
                 headerList.add(paramToSchema(header));
             }
 
-            List<OpenAPISchema.Schema> paramList = new ArrayList<>();
-            for (OpenAPI.Param param : openAPI.param()) {
-                paramList.add(paramToSchema(param));
-            }
+            List<OpenAPISchema.Schema> paramList =
+                RequestDtoSchemaBuilder.build(resolveRequestType(method), openAPI.param(), types);
 
             detail.setSchema(paramList);
             detail.setHeader(headerList);
@@ -141,6 +140,17 @@
         }
     }
 
+    private Class<?> resolveRequestType(Method method) {
+        for (Parameter parameter : method.getParameters()) {
+            Class<?> type = parameter.getType();
+            if (type.isPrimitive() || type == String.class || type.getName().startsWith("java.")) {
+                continue;
+            }
+            return type;
+        }
+        return null;
+    }
+
     private OpenAPISchema.Schema paramToSchema(OpenAPI.Param param) {
         OpenAPISchema.Schema schema = new OpenAPISchema.Schema();
         schema.setName(param.name());
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilder.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilder.java
new file mode 100644
index 0000000..b875a85
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilder.java
@@ -0,0 +1,139 @@
+/*
+ * 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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+import org.apache.streampark.console.core.annotation.OpenAPI;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Builds OpenAPI parameter schemas from request DTO fields and {@link OpenAPI.Param} overrides. */
+public final class RequestDtoSchemaBuilder {
+
+    private static final String TYPE_INTEGER_INT32 = "integer(int32)";
+    private static final String TYPE_BOOLEAN = "boolean";
+
+    private RequestDtoSchemaBuilder() {
+    }
+
+    public static List<OpenAPISchema.Schema> build(Class<?> requestType, OpenAPI.Param[] overrides,
+                                                   Map<String, String> typeNames) {
+        Map<String, OpenAPISchema.Schema> merged = new LinkedHashMap<>();
+        mergeOverrides(merged, overrides, typeNames);
+        mergeRequestFields(merged, requestType, typeNames);
+        return new ArrayList<>(merged.values());
+    }
+
+    private static void mergeOverrides(Map<String, OpenAPISchema.Schema> merged, OpenAPI.Param[] overrides,
+                                       Map<String, String> typeNames) {
+        if (overrides == null) {
+            return;
+        }
+        for (OpenAPI.Param override : overrides) {
+            OpenAPISchema.Schema schema = new OpenAPISchema.Schema();
+            schema.setName(override.name());
+            schema.setBindFor(StringUtils.isBlank(override.bindFor()) ? override.name() : override.bindFor());
+            schema.setRequired(override.required());
+            schema.setDescription(override.description());
+            schema.setDefaultValue(override.defaultValue());
+            schema.setType(resolveType(override.type().getSimpleName(), typeNames));
+            merged.put(schema.getBindFor(), schema);
+        }
+    }
+
+    private static void mergeRequestFields(Map<String, OpenAPISchema.Schema> merged, Class<?> requestType,
+                                           Map<String, String> typeNames) {
+        if (requestType == null) {
+            return;
+        }
+        for (Field field : requestType.getDeclaredFields()) {
+            if (shouldSkipField(merged, field)) {
+                continue;
+            }
+            merged.put(field.getName(), toFieldSchema(field, typeNames));
+        }
+    }
+
+    private static boolean shouldSkipField(Map<String, OpenAPISchema.Schema> merged, Field field) {
+        return "serialVersionUID".equals(field.getName()) || merged.containsKey(field.getName());
+    }
+
+    private static OpenAPISchema.Schema toFieldSchema(Field field, Map<String, String> typeNames) {
+        ApiParam apiParam = field.getAnnotation(ApiParam.class);
+        OpenAPISchema.Schema schema = new OpenAPISchema.Schema();
+        schema.setBindFor(field.getName());
+        schema.setName(apiParam != null && StringUtils.isNotBlank(apiParam.name())
+            ? apiParam.name()
+            : field.getName());
+        schema.setRequired(isRequired(field, apiParam));
+        schema.setDescription(apiParam != null ? apiParam.description() : field.getName());
+        schema.setDefaultValue(apiParam != null ? apiParam.defaultValue() : "");
+        schema.setType(resolveType(field.getType().getSimpleName(), typeNames));
+        return schema;
+    }
+
+    private static boolean isRequired(Field field, ApiParam apiParam) {
+        if (apiParam != null && apiParam.required()) {
+            return true;
+        }
+        return field.getAnnotation(NotNull.class) != null || field.getAnnotation(NotBlank.class) != null;
+    }
+
+    public static String resolveTypeName(String simpleName, Map<String, String> typeNames) {
+        return resolveType(simpleName, typeNames);
+    }
+
+    private static String resolveType(String simpleName, Map<String, String> typeNames) {
+        String mapped = typeNames.get(simpleName);
+        if (mapped != null) {
+            return mapped;
+        }
+        return "string(" + simpleName + ")";
+    }
+
+    public static Map<String, String> defaultTypeNames() {
+        Map<String, String> types = new HashMap<>();
+        types.put("String", "string");
+        types.put("int", TYPE_INTEGER_INT32);
+        types.put("Integer", TYPE_INTEGER_INT32);
+        types.put("Short", TYPE_INTEGER_INT32);
+        types.put("long", "integer(int64)");
+        types.put("Long", "integer(int64)");
+        types.put("double", "number(double)");
+        types.put("Double", "number(double)");
+        types.put("float", "number(float)");
+        types.put("Float", "number(float)");
+        types.put("boolean", TYPE_BOOLEAN);
+        types.put("Boolean", TYPE_BOOLEAN);
+        types.put("byte", "string(byte)");
+        types.put("Byte", "string(byte)");
+        types.put("Date", "string(date)");
+        return types;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ResponseDtoSchemaBuilder.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ResponseDtoSchemaBuilder.java
new file mode 100644
index 0000000..61a293c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/component/ResponseDtoSchemaBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Builds OpenAPI-like field schemas from response DTO classes. */
+public final class ResponseDtoSchemaBuilder {
+
+    private ResponseDtoSchemaBuilder() {
+    }
+
+    public static List<OpenAPISchema.Schema> build(Class<?> responseType, Map<String, String> typeNames) {
+        List<OpenAPISchema.Schema> schemas = new ArrayList<>();
+        if (responseType == null || responseType == Void.class || responseType == void.class) {
+            return schemas;
+        }
+        for (Field field : responseType.getDeclaredFields()) {
+            if ("serialVersionUID".equals(field.getName())) {
+                continue;
+            }
+            ApiParam apiParam = field.getAnnotation(ApiParam.class);
+            OpenAPISchema.Schema schema = new OpenAPISchema.Schema();
+            schema.setBindFor(field.getName());
+            schema.setName(
+                apiParam != null && StringUtils.isNotBlank(apiParam.name()) ? apiParam.name() : field.getName());
+            schema.setRequired(false);
+            schema.setDescription(apiParam != null ? apiParam.description() : field.getName());
+            schema.setDefaultValue(apiParam != null ? apiParam.defaultValue() : "");
+            schema.setType(RequestDtoSchemaBuilder.resolveTypeName(field.getType().getSimpleName(), typeNames));
+            schemas.add(schema);
+        }
+        return schemas;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/AlertController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/AlertController.java
index b299739..35d7319 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/AlertController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/AlertController.java
@@ -19,11 +19,18 @@
 
 import org.apache.streampark.common.util.DateUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.AlertException;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
+import org.apache.streampark.console.core.assembler.AlertAssembler;
 import org.apache.streampark.console.core.bean.AlertTemplate;
 import org.apache.streampark.console.core.entity.AlertConfig;
+import org.apache.streampark.console.core.request.alert.AlertConfigExistsRequest;
+import org.apache.streampark.console.core.request.alert.AlertConfigIdRequest;
+import org.apache.streampark.console.core.request.alert.AlertConfigPageRequest;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
+import org.apache.streampark.console.core.request.alert.AlertSendRequest;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.response.alert.AlertConfigResponse;
 import org.apache.streampark.console.core.service.alert.AlertConfigService;
 import org.apache.streampark.console.core.service.alert.AlertService;
 
@@ -37,6 +44,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 
 import java.util.Date;
@@ -55,50 +63,52 @@
     private final AlertService alertService;
 
     @PostMapping("/add")
-    public RestResponse createAlertConfig(@RequestBody AlertConfigParams params) {
-        boolean save = alertConfigService.save(AlertConfig.of(params));
-        return RestResponse.success(save);
+    public RestResponseBody<Boolean> createAlertConfig(@Valid @RequestBody AlertConfigRequest request) {
+        boolean save = alertConfigService.save(AlertAssembler.toEntity(request));
+        return RestResponseBody.success(save);
     }
 
     @PostMapping("/exists")
-    public RestResponse verifyAlertConfig(@RequestBody AlertConfigParams params) {
-        boolean exist = alertConfigService.exist(AlertConfig.of(params));
-        return RestResponse.success(exist);
+    public RestResponseBody<Boolean> verifyAlertConfig(@Valid @RequestBody AlertConfigExistsRequest request) {
+        AlertConfig probe = new AlertConfig();
+        probe.setAlertName(request.getAlertName());
+        boolean exist = alertConfigService.exist(probe);
+        return RestResponseBody.success(exist);
     }
 
     @PostMapping("/update")
-    public RestResponse updateAlertConfig(@RequestBody AlertConfigParams params) {
-        boolean update = alertConfigService.updateById(AlertConfig.of(params));
-        return RestResponse.success(update);
+    public RestResponseBody<Boolean> updateAlertConfig(@Valid @RequestBody AlertConfigRequest request) {
+        boolean update = alertConfigService.updateById(AlertAssembler.toEntity(request));
+        return RestResponseBody.success(update);
     }
 
     @PostMapping("/get")
-    public RestResponse getAlertConfig(@RequestBody AlertConfigParams params) {
-        AlertConfig alertConfig = alertConfigService.getById(params.getId());
-        return RestResponse.success(AlertConfigParams.of(alertConfig));
+    public RestResponseBody<AlertConfigResponse> getAlertConfig(@Valid @RequestBody AlertConfigIdRequest request) {
+        AlertConfig alertConfig = alertConfigService.getById(request.getId());
+        return RestResponseBody.success(AlertAssembler.toResponse(alertConfig));
     }
 
     @PostMapping("/page")
-    public RestResponse pageAlertConfig(
-                                        @RequestBody AlertConfigParams params, RestRequest request) {
-        IPage<AlertConfigParams> page = alertConfigService.page(params.getUserId(), request);
-        return RestResponse.success(page);
+    public RestResponseBody<IPage<AlertConfigResponse>> pageAlertConfig(
+                                                                        @RequestBody AlertConfigPageRequest request,
+                                                                        RestRequest restRequest) {
+        IPage<AlertConfig> page = alertConfigService.pageEntities(request.getUserId(), restRequest);
+        return RestResponseBody.success(AlertAssembler.toPageResponse(page));
     }
 
     @PostMapping("/list")
-    public RestResponse listAlertConfig() {
-        List<AlertConfig> page = alertConfigService.list();
-        return RestResponse.success(page);
+    public RestResponseBody<List<AlertConfigResponse>> listAlertConfig() {
+        return RestResponseBody.success(AlertAssembler.toListResponse(alertConfigService.list()));
     }
 
     @DeleteMapping("/delete")
-    public RestResponse deleteAlertConfig(@NotNull(message = "{required}") Long id) {
-        boolean result = alertConfigService.removeById(id);
-        return RestResponse.success(result);
+    public RestResponseBody<Boolean> deleteAlertConfig(@NotNull(message = "{required}") @Valid IdRequest request) {
+        boolean result = alertConfigService.removeById(request.getId());
+        return RestResponseBody.success(result);
     }
 
     @PostMapping("/send")
-    public RestResponse sendAlert(Long id) throws AlertException {
+    public RestResponseBody<Boolean> sendAlert(@Valid AlertSendRequest request) throws AlertException {
         AlertTemplate alertTemplate = new AlertTemplate();
         alertTemplate.setTitle("Notify: StreamPark alert job for test");
         alertTemplate.setJobName("StreamPark alert job for test");
@@ -111,6 +121,6 @@
             DateUtils.format(date, DateUtils.fullFormat(), TimeZone.getDefault()));
         alertTemplate.setEndTime(DateUtils.format(date, DateUtils.fullFormat(), TimeZone.getDefault()));
         alertTemplate.setDuration("");
-        return RestResponse.success(alertService.alert(id, alertTemplate));
+        return RestResponseBody.success(alertService.alert(request.getId(), alertTemplate));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ExternalLinkController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ExternalLinkController.java
index 6a16ba0..e43cc6c 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ExternalLinkController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ExternalLinkController.java
@@ -18,8 +18,14 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.common.util.AssertUtils;
-import org.apache.streampark.console.base.domain.RestResponse;
-import org.apache.streampark.console.core.entity.ExternalLink;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.ExternalLinkAssembler;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.externallink.ExternalLinkCreateRequest;
+import org.apache.streampark.console.core.request.externallink.ExternalLinkRenderRequest;
+import org.apache.streampark.console.core.request.externallink.ExternalLinkUpdateRequest;
+import org.apache.streampark.console.core.response.externallink.ExternalLinkResponse;
 import org.apache.streampark.console.core.service.ExternalLinkService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -30,11 +36,9 @@
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
 
 import java.util.List;
 
@@ -49,38 +53,35 @@
 
     @PostMapping("/list")
     @RequiresPermissions("externalLink:view")
-    public RestResponse list() {
-        List<ExternalLink> externalLink = externalLinkService.list();
-        return RestResponse.success(externalLink);
+    public RestResponseBody<List<ExternalLinkResponse>> list() {
+        return RestResponseBody.success(ExternalLinkAssembler.toListResponse(externalLinkService.list()));
     }
 
     @PostMapping("/render")
-    public RestResponse render(
-                               @NotNull(message = "The flink app id cannot be null") @RequestParam("appId") Long appId) {
-        List<ExternalLink> renderedExternalLink = externalLinkService.render(appId);
-        return RestResponse.success(renderedExternalLink);
+    public RestResponseBody<List<ExternalLinkResponse>> render(@Valid ExternalLinkRenderRequest request) {
+        return RestResponseBody.success(
+            ExternalLinkAssembler.toListResponse(externalLinkService.render(request.getAppId())));
     }
 
     @PostMapping("/create")
     @RequiresPermissions("externalLink:create")
-    public RestResponse create(@Valid ExternalLink externalLink) {
-        externalLinkService.create(externalLink);
-        return RestResponse.success();
+    public RestResponseBody<Void> create(@Valid @FormOrJson ExternalLinkCreateRequest request) {
+        externalLinkService.create(ExternalLinkAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("/update")
     @RequiresPermissions("externalLink:update")
-    public RestResponse update(@Valid ExternalLink externalLink) {
-        AssertUtils.notNull(externalLink.getId(), "The link id cannot be null");
-        externalLinkService.update(externalLink);
-        return RestResponse.success();
+    public RestResponseBody<Void> update(@Valid @FormOrJson ExternalLinkUpdateRequest request) {
+        AssertUtils.notNull(request.getId(), "The link id cannot be null");
+        externalLinkService.update(ExternalLinkAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("/delete")
     @RequiresPermissions("externalLink:delete")
-    public RestResponse delete(
-                               @NotNull(message = "The link id cannot be null") @RequestParam("id") Long id) {
-        externalLinkService.removeById(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson IdRequest request) {
+        externalLinkService.removeById(request.getId());
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationController.java
index 2731443..d3f545f 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationController.java
@@ -20,14 +20,37 @@
 import org.apache.streampark.common.util.Utils;
 import org.apache.streampark.common.util.YarnUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.AppChangeEvent;
 import org.apache.streampark.console.core.annotation.Permission;
-import org.apache.streampark.console.core.entity.ApplicationLog;
+import org.apache.streampark.console.core.assembler.AppLogAssembler;
+import org.apache.streampark.console.core.assembler.FlinkApplicationAssembler;
 import org.apache.streampark.console.core.entity.FlinkApplication;
-import org.apache.streampark.console.core.entity.FlinkApplicationBackup;
 import org.apache.streampark.console.core.enums.AppExistsStateEnum;
+import org.apache.streampark.console.core.request.app.AppBackupDeleteRequest;
+import org.apache.streampark.console.core.request.app.AppBackupQueryRequest;
+import org.apache.streampark.console.core.request.app.AppOptLogDeleteRequest;
+import org.apache.streampark.console.core.request.app.AppOptLogQueryRequest;
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCancelRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCheckNameRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCheckSavepointPathRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppConfigRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCopyRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppGetMainRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppK8sLogRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppListQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppMappingRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppUpdateRequest;
+import org.apache.streampark.console.core.response.app.AppBackupResponse;
+import org.apache.streampark.console.core.response.app.AppOptLogResponse;
+import org.apache.streampark.console.core.response.flink.FlinkAppDashboardResponse;
+import org.apache.streampark.console.core.response.flink.FlinkAppResponse;
 import org.apache.streampark.console.core.service.ResourceService;
 import org.apache.streampark.console.core.service.application.ApplicationLogService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationActionService;
@@ -45,6 +68,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
@@ -76,185 +101,188 @@
     private ResourceService resourceService;
 
     @PostMapping("get")
-    @Permission(app = "#app.id")
+    @Permission(app = "#request.id")
     @RequiresPermissions("app:detail")
-    public RestResponse get(FlinkApplication app) {
-        FlinkApplication application = applicationManageService.getApp(app.getId());
-        return RestResponse.success(application);
+    public RestResponseBody<FlinkAppResponse> get(@Valid FlinkAppIdRequest request) {
+        FlinkApplication application = applicationManageService.getApp(request.getId());
+        FlinkAppResponse response = FlinkApplicationAssembler.toResponse(application);
+        return RestResponseBody.success(response);
     }
 
-    @Permission(team = "#app.teamId")
+    @Permission(team = "#request.teamId")
     @PostMapping("create")
     @RequiresPermissions("app:create")
-    public RestResponse create(FlinkApplication app) throws IOException {
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson FlinkAppCreateRequest request) throws IOException {
+        FlinkApplication app = FlinkApplicationAssembler.toEntity(request);
         boolean saved = applicationManageService.create(app);
-        return RestResponse.success(saved);
+        return RestResponseBody.success(saved);
     }
 
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("copy")
     @RequiresPermissions("app:copy")
-    public RestResponse copy(FlinkApplication app) throws IOException {
-        applicationManageService.copy(app);
-        return RestResponse.success();
+    public RestResponseBody<Void> copy(@Valid @FormOrJson FlinkAppCopyRequest request) throws IOException {
+        applicationManageService.copy(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @AppChangeEvent
-    @Permission(app = "#app.id")
+    @Permission(app = "#request.id")
     @PostMapping("update")
     @RequiresPermissions("app:update")
-    public RestResponse update(FlinkApplication app) {
-        applicationManageService.update(app);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson FlinkAppUpdateRequest request) {
+        applicationManageService.update(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("dashboard")
-    @Permission(team = "#teamId")
-    public RestResponse dashboard(Long teamId) {
-        Map<String, Serializable> dashboardMap = applicationInfoService.getDashboardDataMap(teamId);
-        return RestResponse.success(dashboardMap);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<FlinkAppDashboardResponse> dashboard(@Valid TeamIdRequest request) {
+        Map<String, Serializable> dashboardMap = applicationInfoService.getDashboardDataMap(request.getTeamId());
+        return RestResponseBody.success(FlinkApplicationAssembler.toDashboardResponse(dashboardMap));
     }
 
     @PostMapping("list")
-    @Permission(team = "#app.teamId")
+    @Permission(team = "#query.teamId")
     @RequiresPermissions("app:view")
-    public RestResponse list(FlinkApplication app, RestRequest request) {
-        IPage<FlinkApplication> applicationList = applicationManageService.page(app, request);
-        return RestResponse.success(applicationList);
+    public RestResponseBody<IPage<FlinkAppResponse>> list(@Valid FlinkAppListQueryRequest query, RestRequest request) {
+        FlinkApplication appParam = FlinkApplicationAssembler.toEntity(query);
+        IPage<FlinkApplication> applicationList = applicationManageService.page(appParam, request);
+        return RestResponseBody.success(FlinkApplicationAssembler.toPageResponse(applicationList));
     }
 
     @AppChangeEvent
     @PostMapping("mapping")
-    @Permission(app = "#app.id")
+    @Permission(app = "#request.id")
     @RequiresPermissions("app:mapping")
-    public RestResponse mapping(FlinkApplication app) {
-        boolean flag = applicationManageService.mapping(app);
-        return RestResponse.success(flag);
+    public RestResponseBody<Boolean> mapping(@Valid @FormOrJson FlinkAppMappingRequest request) {
+        boolean flag = applicationManageService.mapping(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(flag);
     }
 
     @AppChangeEvent
-    @Permission(app = "#app.id")
+    @Permission(app = "#request.id")
     @PostMapping("revoke")
     @RequiresPermissions("app:release")
-    public RestResponse revoke(FlinkApplication app) {
-        applicationActionService.revoke(app.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> revoke(@Valid @FormOrJson FlinkAppIdRequest request) {
+        applicationActionService.revoke(request.getId());
+        return RestResponseBody.success();
     }
 
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("check/start")
     @RequiresPermissions("app:start")
-    public RestResponse checkStart(FlinkApplication app) {
-        AppExistsStateEnum stateEnum = applicationInfoService.checkStart(app.getId());
-        return RestResponse.success(stateEnum.get());
+    public RestResponseBody<Integer> checkStart(@Valid FlinkAppIdRequest request) {
+        AppExistsStateEnum stateEnum = applicationInfoService.checkStart(request.getId());
+        return RestResponseBody.success(stateEnum.get());
     }
 
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("start")
     @RequiresPermissions("app:start")
-    public RestResponse start(FlinkApplication app) throws Exception {
-        applicationActionService.start(app, false);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> start(@Valid @FormOrJson FlinkAppStartRequest request) throws Exception {
+        applicationActionService.start(FlinkApplicationAssembler.toEntity(request), false);
+        return RestResponseBody.success(true);
     }
 
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("cancel")
     @RequiresPermissions("app:cancel")
-    public RestResponse cancel(FlinkApplication app) throws Exception {
-        applicationActionService.cancel(app);
-        return RestResponse.success();
+    public RestResponseBody<Void> cancel(@Valid @FormOrJson FlinkAppCancelRequest request) throws Exception {
+        applicationActionService.cancel(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     /** force stop(stop normal start or in progress) */
-    @Permission(app = "#app.id")
+    @Permission(app = "#request.id")
     @PostMapping("abort")
     @RequiresPermissions("app:cancel")
-    public RestResponse abort(FlinkApplication app) {
-        applicationActionService.abort(app.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> abort(@Valid @FormOrJson FlinkAppIdRequest request) {
+        applicationActionService.abort(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("yarn")
-    public RestResponse yarn() {
-        return RestResponse.success(YarnUtils.getRMWebAppProxyURL());
+    public RestResponseBody<String> yarn() {
+        return RestResponseBody.success(YarnUtils.getRMWebAppProxyURL());
     }
 
     @PostMapping("name")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse yarnName(FlinkApplication app) {
-        String yarnName = applicationInfoService.getYarnName(app.getConfig());
-        return RestResponse.success(yarnName);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<String> yarnName(FlinkAppConfigRequest request) {
+        String yarnName = applicationInfoService.getYarnName(request.getConfig());
+        return RestResponseBody.success(yarnName);
     }
 
     @PostMapping("check/name")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse checkName(FlinkApplication app) {
-        AppExistsStateEnum exists = applicationInfoService.checkExists(app);
-        return RestResponse.success(exists.get());
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<Integer> checkName(@Valid FlinkAppCheckNameRequest request) {
+        AppExistsStateEnum exists = applicationInfoService.checkExists(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(exists.get());
     }
 
     @PostMapping("read_conf")
-    public RestResponse readConf(FlinkApplication app) throws IOException {
-        String config = applicationInfoService.readConf(app.getConfig());
-        return RestResponse.success(config);
+    public RestResponseBody<String> readConf(FlinkAppConfigRequest request) throws IOException {
+        String config = applicationInfoService.readConf(request.getConfig());
+        return RestResponseBody.success(config);
     }
 
     @PostMapping("main")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse getMain(FlinkApplication application) {
-        String mainClass = applicationInfoService.getMain(application);
-        return RestResponse.success(mainClass);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<String> getMain(FlinkAppGetMainRequest request) {
+        String mainClass = applicationInfoService.getMain(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(mainClass);
     }
 
     @PostMapping("backups")
-    @Permission(app = "#backUp.appId", team = "#backUp.teamId")
-    public RestResponse backups(FlinkApplicationBackup backUp, RestRequest request) {
-        IPage<FlinkApplicationBackup> backups = backUpService.getPage(backUp, request);
-        return RestResponse.success(backups);
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<AppBackupResponse>> backups(AppBackupQueryRequest query, RestRequest request) {
+        return RestResponseBody.success(
+            AppLogAssembler.toBackupPage(backUpService.getPage(AppLogAssembler.toEntity(query), request)));
     }
 
     @PostMapping("opt_log")
-    @Permission(app = "#applicationLog.appId", team = "#applicationLog.teamId")
-    public RestResponse log(ApplicationLog applicationLog, RestRequest request) {
-        IPage<ApplicationLog> applicationList = applicationLogService.getPage(applicationLog, request);
-        return RestResponse.success(applicationList);
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<AppOptLogResponse>> log(AppOptLogQueryRequest query, RestRequest request) {
+        return RestResponseBody.success(
+            AppLogAssembler.toOptLogPage(applicationLogService.getPage(AppLogAssembler.toEntity(query), request)));
     }
 
-    @Permission(app = "#applicationLog.appId", team = "#applicationLog.teamId")
+    @Permission(app = "#request.appId", team = "#request.teamId")
     @PostMapping("delete/opt_log")
     @RequiresPermissions("app:delete")
-    public RestResponse deleteLog(ApplicationLog applicationLog) {
-        Boolean deleted = applicationLogService.delete(applicationLog);
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> deleteLog(@Valid @FormOrJson AppOptLogDeleteRequest request) {
+        Boolean deleted = applicationLogService.delete(AppLogAssembler.toEntity(request));
+        return RestResponseBody.success(deleted);
     }
 
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("delete")
     @RequiresPermissions("app:delete")
-    public RestResponse delete(FlinkApplication app) throws InternalException {
-        Boolean deleted = applicationManageService.remove(app.getId());
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson FlinkAppIdRequest request) throws InternalException {
+        Boolean deleted = applicationManageService.remove(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
-    @Permission(app = "#backUp.appId")
+    @Permission(app = "#request.appId")
     @PostMapping("delete/backup")
-    public RestResponse deleteBackup(FlinkApplicationBackup backUp) throws InternalException {
-        Boolean deleted = backUpService.removeById(backUp.getId());
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> deleteBackup(@Valid @FormOrJson AppBackupDeleteRequest request) throws InternalException {
+        Boolean deleted = backUpService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("check/jar")
-    public RestResponse checkJar(String jar) throws IOException {
+    public RestResponseBody<Boolean> checkJar(String jar) throws IOException {
         Utils.requireCheckJarFile(new File(jar).toURI().toURL());
-        return RestResponse.success(true);
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("verify_schema")
-    public RestResponse verifySchema(String path) {
+    public RestResponseBody<Boolean> verifySchema(String path) {
         final URI uri = URI.create(path);
         final String scheme = uri.getScheme();
         final String pathPart = uri.getPath();
-        RestResponse restResponse = RestResponse.success(true);
+        RestResponseBody<Boolean> restResponse = RestResponseBody.success(true);
         String error = null;
         if (scheme == null) {
             error =
@@ -266,25 +294,25 @@
             error = "Cannot use the root directory for checkpoints.";
         }
         if (error != null) {
-            restResponse = RestResponse.success(false).message(error);
+            restResponse = RestResponseBody.success(false).message(error);
         }
         return restResponse;
     }
 
     @PostMapping("check/savepoint_path")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse checkSavepointPath(FlinkApplication app) throws Exception {
-        String error = applicationInfoService.checkSavepointPath(app);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<Boolean> checkSavepointPath(FlinkAppCheckSavepointPathRequest request) throws Exception {
+        String error = applicationInfoService.checkSavepointPath(FlinkApplicationAssembler.toEntity(request));
         if (error == null) {
-            return RestResponse.success(true);
+            return RestResponseBody.success(true);
         }
-        return RestResponse.success(false).message(error);
+        return RestResponseBody.success(false).message(error);
     }
 
-    @Permission(app = "#id")
+    @Permission(app = "#request.id")
     @PostMapping("k8s_log")
-    public RestResponse k8sStartLog(Long id, Integer offset, Integer limit) throws Exception {
-        String resp = applicationInfoService.k8sStartLog(id, offset, limit);
-        return RestResponse.success(resp);
+    public RestResponseBody<String> k8sStartLog(FlinkAppK8sLogRequest request) throws Exception {
+        String resp = applicationInfoService.k8sStartLog(request.getId(), request.getOffset(), request.getLimit());
+        return RestResponseBody.success(resp);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationHistoryController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationHistoryController.java
index b4e93c4..b56db50 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationHistoryController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkApplicationHistoryController.java
@@ -18,7 +18,8 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.common.enums.FlinkDeployMode;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.request.flink.FlinkHistoryDeployModeRequest;
 import org.apache.streampark.console.core.service.application.FlinkApplicationInfoService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -44,53 +45,53 @@
 
     @PostMapping("k8s_namespaces")
     @RequiresPermissions("app:create")
-    public RestResponse listK8sNamespace() {
+    public RestResponseBody<List<String>> listK8sNamespace() {
         List<String> namespaces = applicationInfoService.listRecentK8sNamespace();
-        return RestResponse.success(namespaces);
+        return RestResponseBody.success(namespaces);
     }
 
     @PostMapping("session_cluster_ids")
     @RequiresPermissions("app:create")
-    public RestResponse listSessionClusterId(int deployMode) {
+    public RestResponseBody<List<String>> listSessionClusterId(FlinkHistoryDeployModeRequest request) {
         List<String> clusterIds;
-        switch (FlinkDeployMode.of(deployMode)) {
+        switch (FlinkDeployMode.of(request.getDeployMode())) {
             case KUBERNETES_NATIVE_SESSION:
             case YARN_SESSION:
             case REMOTE:
-                clusterIds = applicationInfoService.listRecentK8sClusterId(deployMode);
+                clusterIds = applicationInfoService.listRecentK8sClusterId(request.getDeployMode());
                 break;
             default:
                 clusterIds = new ArrayList<>(0);
                 break;
         }
-        return RestResponse.success(clusterIds);
+        return RestResponseBody.success(clusterIds);
     }
 
     @PostMapping("flink_base_images")
     @RequiresPermissions("app:create")
-    public RestResponse listFlinkBaseImage() {
+    public RestResponseBody<List<String>> listFlinkBaseImage() {
         List<String> images = applicationInfoService.listRecentFlinkBaseImage();
-        return RestResponse.success(images);
+        return RestResponseBody.success(images);
     }
 
     @PostMapping("flink_pod_templates")
     @RequiresPermissions("app:create")
-    public RestResponse listPodTemplate() {
+    public RestResponseBody<List<String>> listPodTemplate() {
         List<String> templates = applicationInfoService.listRecentK8sPodTemplate();
-        return RestResponse.success(templates);
+        return RestResponseBody.success(templates);
     }
 
     @PostMapping("flink_jm_pod_templates")
     @RequiresPermissions("app:create")
-    public RestResponse listJmPodTemplate() {
+    public RestResponseBody<List<String>> listJmPodTemplate() {
         List<String> templates = applicationInfoService.listRecentK8sJmPodTemplate();
-        return RestResponse.success(templates);
+        return RestResponseBody.success(templates);
     }
 
     @PostMapping("flink_tm_pod_templates")
     @RequiresPermissions("app:create")
-    public RestResponse listTmPodTemplate() {
+    public RestResponseBody<List<String>> listTmPodTemplate() {
         List<String> templates = applicationInfoService.listRecentK8sTmPodTemplate();
-        return RestResponse.success(templates);
+        return RestResponseBody.success(templates);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkClusterController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkClusterController.java
index d084177..f256726 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkClusterController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkClusterController.java
@@ -19,10 +19,19 @@
 
 import org.apache.streampark.common.enums.ClusterState;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.FlinkClusterAssembler;
 import org.apache.streampark.console.core.bean.ResponseResult;
 import org.apache.streampark.console.core.entity.FlinkCluster;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterCheckRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterPageQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkClusterUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkClusterCheckResponse;
+import org.apache.streampark.console.core.response.flink.FlinkClusterResponse;
 import org.apache.streampark.console.core.service.FlinkClusterService;
 import org.apache.streampark.console.core.util.ServiceHelper;
 
@@ -36,6 +45,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.List;
 
 @Slf4j
@@ -48,75 +59,78 @@
     private FlinkClusterService flinkClusterService;
 
     @PostMapping("page")
-    public RestResponse findPage(FlinkCluster flinkCluster, RestRequest restRequest) {
+    public RestResponseBody<IPage<FlinkClusterResponse>> findPage(FlinkClusterPageQueryRequest query,
+                                                                  RestRequest restRequest) {
+        FlinkCluster flinkCluster = FlinkClusterAssembler.toEntity(query);
         IPage<FlinkCluster> flinkClusters = flinkClusterService.findPage(flinkCluster, restRequest);
-        return RestResponse.success(flinkClusters);
+        return RestResponseBody.success(FlinkClusterAssembler.toPageResponse(flinkClusters));
     }
 
     @PostMapping("alive")
-    public RestResponse listAvailableCluster() {
+    public RestResponseBody<List<FlinkClusterResponse>> listAvailableCluster() {
         List<FlinkCluster> flinkClusters = flinkClusterService.listAvailableCluster();
-        return RestResponse.success(flinkClusters);
+        return RestResponseBody.success(FlinkClusterAssembler.toListResponse(flinkClusters));
     }
 
     @PostMapping("list")
-    public RestResponse list() {
+    public RestResponseBody<java.util.List<FlinkClusterResponse>> list() {
         List<FlinkCluster> flinkClusters = flinkClusterService.list();
-        return RestResponse.success(flinkClusters);
+        return RestResponseBody.success(FlinkClusterAssembler.toListResponse(flinkClusters));
     }
 
     @PostMapping("remote_url")
-    public RestResponse remoteUrl(Long id) {
-        FlinkCluster cluster = flinkClusterService.getById(id);
-        return RestResponse.success(cluster.getAddress());
+    public RestResponseBody<String> remoteUrl(@Valid IdRequest request) {
+        FlinkCluster cluster = flinkClusterService.getById(request.getId());
+        return RestResponseBody.success(cluster.getAddress());
     }
 
     @PostMapping("check")
-    public RestResponse check(FlinkCluster cluster) {
-        ResponseResult checkResult = flinkClusterService.check(cluster);
-        return RestResponse.success(checkResult);
+    public RestResponseBody<FlinkClusterCheckResponse> check(FlinkClusterCheckRequest request) {
+        ResponseResult checkResult = flinkClusterService.check(FlinkClusterAssembler.toEntity(request));
+        return RestResponseBody.success(FlinkClusterAssembler.toCheckResponse(checkResult));
     }
 
     @PostMapping("create")
     @RequiresPermissions("cluster:create")
-    public RestResponse create(FlinkCluster cluster) {
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson FlinkClusterCreateRequest request) {
         Long userId = ServiceHelper.getUserId();
-        Boolean success = flinkClusterService.create(cluster, userId);
-        return RestResponse.success(success);
+        Boolean success = flinkClusterService.create(FlinkClusterAssembler.toEntity(request), userId);
+        return RestResponseBody.success(success);
     }
 
     @PostMapping("update")
     @RequiresPermissions("cluster:update")
-    public RestResponse update(FlinkCluster cluster) {
-        flinkClusterService.update(cluster);
-        return RestResponse.success();
+    public RestResponseBody<Void> update(@Valid @FormOrJson FlinkClusterUpdateRequest request) {
+        flinkClusterService.update(FlinkClusterAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("get")
-    public RestResponse get(Long id) throws InternalException {
-        FlinkCluster cluster = flinkClusterService.getById(id);
-        return RestResponse.success(cluster);
+    public RestResponseBody<FlinkClusterResponse> get(@Valid IdRequest request) throws InternalException {
+        FlinkCluster cluster = flinkClusterService.getById(request.getId());
+        return RestResponseBody.success(FlinkClusterAssembler.toResponse(cluster));
     }
 
     @PostMapping("start")
-    public RestResponse start(FlinkCluster cluster) {
-        flinkClusterService.updateClusterState(cluster.getId(), ClusterState.STARTING);
-        flinkClusterService.start(cluster);
-        return RestResponse.success();
+    public RestResponseBody<Void> start(@Valid @FormOrJson IdRequest request) {
+        flinkClusterService.updateClusterState(request.getId(), ClusterState.STARTING);
+        flinkClusterService.start(FlinkClusterAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("shutdown")
-    public RestResponse shutdown(FlinkCluster cluster) {
-        if (flinkClusterService.allowShutdownCluster(cluster)) {
+    public RestResponseBody<Void> shutdown(@Valid @FormOrJson IdRequest request) {
+        FlinkCluster cluster = FlinkClusterAssembler.toEntity(request);
+        if (cluster != null && flinkClusterService.allowShutdownCluster(cluster)) {
             flinkClusterService.updateClusterState(cluster.getId(), ClusterState.CANCELLING);
             flinkClusterService.shutdown(cluster);
         }
-        return RestResponse.success();
+        return RestResponseBody.success();
     }
 
     @PostMapping("delete")
-    public RestResponse delete(FlinkCluster cluster) {
-        flinkClusterService.remove(cluster.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson IdRequest request) {
+        flinkClusterService.remove(request.getId());
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkConfigController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkConfigController.java
index 3d0edb5..31efa46 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkConfigController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkConfigController.java
@@ -19,9 +19,15 @@
 
 import org.apache.streampark.common.util.HadoopConfigUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
-import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.FlinkConfAssembler;
 import org.apache.streampark.console.core.entity.FlinkApplicationConfig;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkConfListQueryRequest;
+import org.apache.streampark.console.core.response.flink.FlinkConfHadoopResponse;
+import org.apache.streampark.console.core.response.flink.FlinkConfResponse;
 import org.apache.streampark.console.core.service.application.FlinkApplicationConfigService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -35,6 +41,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.List;
 import java.util.Map;
 
@@ -48,42 +56,44 @@
     private FlinkApplicationConfigService applicationConfigService;
 
     @PostMapping("get")
-    public RestResponse get(Long id) {
-        FlinkApplicationConfig config = applicationConfigService.get(id);
-        return RestResponse.success(config);
+    public RestResponseBody<FlinkConfResponse> get(@Valid IdRequest request) {
+        FlinkApplicationConfig config = applicationConfigService.get(request.getId());
+        return RestResponseBody.success(FlinkConfAssembler.toResponse(config));
     }
 
     @PostMapping("template")
-    public RestResponse template() {
+    public RestResponseBody<String> template() {
         String config = applicationConfigService.readTemplate();
-        return RestResponse.success(config);
+        return RestResponseBody.success(config);
     }
 
     @PostMapping("list")
-    public RestResponse list(FlinkApplicationConfig config, RestRequest request) {
+    public RestResponseBody<IPage<FlinkConfResponse>> list(FlinkConfListQueryRequest query, RestRequest request) {
+        FlinkApplicationConfig config = FlinkConfAssembler.toEntity(query);
         IPage<FlinkApplicationConfig> page = applicationConfigService.getPage(config, request);
-        return RestResponse.success(page);
+        return RestResponseBody.success(FlinkConfAssembler.toPageResponse(page));
     }
 
     @PostMapping("history")
-    public RestResponse history(FlinkApplication application) {
-        List<FlinkApplicationConfig> history = applicationConfigService.list(application.getId());
-        return RestResponse.success(history);
+    public RestResponseBody<List<FlinkConfResponse>> history(@Valid FlinkAppIdRequest request) {
+        List<FlinkApplicationConfig> history =
+            applicationConfigService.list(FlinkConfAssembler.toAppId(request));
+        return RestResponseBody.success(FlinkConfAssembler.toListResponse(history));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("conf:delete")
-    public RestResponse delete(Long id) {
-        Boolean deleted = applicationConfigService.removeById(id);
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson IdRequest request) {
+        Boolean deleted = applicationConfigService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("sys_hadoop_conf")
     @RequiresPermissions("app:create")
-    public RestResponse getSystemHadoopConfig() {
+    public RestResponseBody<FlinkConfHadoopResponse> getSystemHadoopConfig() {
         Map<String, Map<String, String>> result = ImmutableMap.of(
             "hadoop", HadoopConfigUtils.readSystemHadoopConf(),
             "hive", HadoopConfigUtils.readSystemHiveConf());
-        return RestResponse.success(result);
+        return RestResponseBody.success(FlinkConfAssembler.toHadoopResponse(result));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkEnvController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkEnvController.java
index 56e984c..69963e2 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkEnvController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkEnvController.java
@@ -18,9 +18,18 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.exception.ApiAlertException;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.FlinkEnvAssembler;
 import org.apache.streampark.console.core.entity.FlinkEnv;
 import org.apache.streampark.console.core.enums.FlinkEnvCheckEnum;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvCheckRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvPageQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkEnvUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkEnvResponse;
 import org.apache.streampark.console.core.service.FlinkEnvService;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -31,6 +40,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.List;
 
 @Slf4j
@@ -43,62 +54,65 @@
     private FlinkEnvService flinkEnvService;
 
     @PostMapping("page")
-    public RestResponse findPage(FlinkEnv flinkEnv, RestRequest restRequest) {
+    public RestResponseBody<IPage<FlinkEnvResponse>> findPage(FlinkEnvPageQueryRequest query, RestRequest restRequest) {
+        FlinkEnv flinkEnv = FlinkEnvAssembler.toEntity(query);
         IPage<FlinkEnv> envs = flinkEnvService.findPage(flinkEnv, restRequest);
-        return RestResponse.success(envs);
+        return RestResponseBody.success(FlinkEnvAssembler.toPageResponse(envs));
     }
+
     @PostMapping("list")
-    public RestResponse list() {
+    public RestResponseBody<List<FlinkEnvResponse>> list() {
         List<FlinkEnv> flinkEnvList = flinkEnvService.list();
-        return RestResponse.success(flinkEnvList);
+        return RestResponseBody.success(FlinkEnvAssembler.toListResponse(flinkEnvList));
     }
 
     @PostMapping("check")
-    public RestResponse check(FlinkEnv version) {
-        FlinkEnvCheckEnum checkResp = flinkEnvService.check(version);
-        return RestResponse.success(checkResp.getCode());
+    public RestResponseBody<Integer> check(FlinkEnvCheckRequest request) {
+        FlinkEnvCheckEnum checkResp = flinkEnvService.check(FlinkEnvAssembler.toEntity(request));
+        return RestResponseBody.success(checkResp.getCode());
     }
 
     @PostMapping("create")
-    public RestResponse create(FlinkEnv version) throws Exception {
-        flinkEnvService.create(version);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson FlinkEnvCreateRequest request) {
+        flinkEnvService.create(FlinkEnvAssembler.toEntity(request));
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("get")
-    public RestResponse get(Long id) throws Exception {
-        FlinkEnv flinkEnv = flinkEnvService.getById(id);
+    public RestResponseBody<FlinkEnvResponse> get(@Valid IdRequest request) throws Exception {
+        FlinkEnv flinkEnv = flinkEnvService.getById(request.getId());
+        ApiAlertException.throwIfNull(flinkEnv, "Flink environment not found.");
         flinkEnv.unzipFlinkConf();
-        return RestResponse.success(flinkEnv);
+        return RestResponseBody.success(FlinkEnvAssembler.toResponse(flinkEnv));
     }
 
     @PostMapping("sync")
-    public RestResponse sync(Long id) throws Exception {
-        flinkEnvService.syncConf(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> sync(@Valid @FormOrJson IdRequest request) throws Exception {
+        flinkEnvService.syncConf(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("update")
-    public RestResponse update(FlinkEnv version) {
-        flinkEnvService.update(version);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson FlinkEnvUpdateRequest request) {
+        flinkEnvService.update(FlinkEnvAssembler.toEntity(request));
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("delete")
-    public RestResponse delete(Long id) {
-        flinkEnvService.removeById(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson IdRequest request) {
+        flinkEnvService.removeById(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("validity")
-    public RestResponse validity(FlinkEnv version) {
-        flinkEnvService.validity(version.getId());
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> validity(FlinkEnvCheckRequest request) {
+        flinkEnvService.validity(request.getId());
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("default")
-    public RestResponse setDefault(Long id) {
-        flinkEnvService.setDefault(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> setDefault(@Valid @FormOrJson IdRequest request) {
+        flinkEnvService.setDefault(request.getId());
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPipelineController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPipelineController.java
index b4e4aa2..8be66b8 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPipelineController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPipelineController.java
@@ -17,10 +17,15 @@
 
 package org.apache.streampark.console.core.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.FlinkPipelineAssembler;
 import org.apache.streampark.console.core.bean.AppBuildDockerResolvedDetail;
 import org.apache.streampark.console.core.entity.ApplicationBuildPipeline;
+import org.apache.streampark.console.core.request.flink.FlinkPipelineBuildRequest;
+import org.apache.streampark.console.core.request.flink.FlinkPipelineDetailRequest;
+import org.apache.streampark.console.core.response.flink.FlinkPipelineDetailResponse;
 import org.apache.streampark.console.core.service.application.FlinkApplicationBuildPipelineService;
 import org.apache.streampark.flink.packer.pipeline.DockerResolvedSnapshot;
 import org.apache.streampark.flink.packer.pipeline.PipelineTypeEnum;
@@ -34,8 +39,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.HashMap;
-import java.util.Map;
+import javax.validation.Valid;
+
 import java.util.Optional;
 
 @Slf4j
@@ -47,33 +52,35 @@
     @Autowired
     private FlinkApplicationBuildPipelineService appBuildPipeService;
 
-    @Permission(app = "#appId")
+    @Permission(app = "#request.appId")
     @PostMapping("build")
     @RequiresPermissions("app:create")
-    public RestResponse buildApplication(Long appId, boolean forceBuild) throws Exception {
-        boolean actionResult = appBuildPipeService.buildApplication(appId, forceBuild);
-        return RestResponse.success(actionResult);
+    public RestResponseBody<Boolean> buildApplication(@Valid @FormOrJson FlinkPipelineBuildRequest request) throws Exception {
+        boolean actionResult = appBuildPipeService.buildApplication(request.getAppId(), request.isForceBuild());
+        return RestResponseBody.success(actionResult);
     }
 
     /**
      * Get application building pipeline progress detail.
      *
-     * @param appId application id
-     * @return "pipeline" -> pipeline details, "docker" -> docker resolved snapshot
+     * @param request application id
+     * @return pipeline and docker resolved snapshot details
      */
     @PostMapping("/detail")
-    @Permission(app = "#appId")
+    @Permission(app = "#request.appId")
     @RequiresPermissions("app:view")
-    public RestResponse getBuildProgressDetail(Long appId) {
-        Map<String, Object> details = new HashMap<>(0);
+    public RestResponseBody<FlinkPipelineDetailResponse> getBuildProgressDetail(@Valid FlinkPipelineDetailRequest request) {
+        Long appId = request.getAppId();
         Optional<ApplicationBuildPipeline> pipeline = appBuildPipeService.getCurrentBuildPipeline(appId);
-        details.put("pipeline", pipeline.map(ApplicationBuildPipeline::toView).orElse(null));
+        ApplicationBuildPipeline.View pipelineView =
+            pipeline.map(ApplicationBuildPipeline::toView).orElse(null);
 
+        AppBuildDockerResolvedDetail dockerDetail = null;
         if (pipeline.isPresent()
             && PipelineTypeEnum.FLINK_NATIVE_K8S_APPLICATION == pipeline.get().getPipeType()) {
             DockerResolvedSnapshot dockerProgress = appBuildPipeService.getDockerProgressDetailSnapshot(appId);
-            details.put("docker", AppBuildDockerResolvedDetail.of(dockerProgress));
+            dockerDetail = AppBuildDockerResolvedDetail.of(dockerProgress);
         }
-        return RestResponse.success(details);
+        return RestResponseBody.success(FlinkPipelineAssembler.toDetailResponse(pipelineView, dockerDetail));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPodTemplateController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPodTemplateController.java
index 1865583..9e1e7f3 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPodTemplateController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkPodTemplateController.java
@@ -18,7 +18,10 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.common.util.HostsUtils;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.request.flink.FlinkPodTemplateExtractRequest;
+import org.apache.streampark.console.core.request.flink.FlinkPodTemplateHostAliasRequest;
+import org.apache.streampark.console.core.request.flink.FlinkPodTemplatePreviewRequest;
 import org.apache.streampark.flink.kubernetes.PodTemplateParser;
 
 import org.apache.commons.lang3.StringUtils;
@@ -29,6 +32,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -42,26 +47,26 @@
 public class FlinkPodTemplateController {
 
     @PostMapping("sys_hosts")
-    public RestResponse getHosts() {
-        // hostname -> ipv4
+    public RestResponseBody<List<String>> getHosts() {
         Map<String, String> hostMap = HostsUtils.getSystemHostsAsJava(true);
         List<String> friendlyHosts = hostMap.entrySet().stream()
             .map(e -> e.getKey() + ":" + e.getValue())
             .collect(Collectors.toList());
-        return RestResponse.success(friendlyHosts);
+        return RestResponseBody.success(friendlyHosts);
     }
 
     @PostMapping("init")
-    public RestResponse getInitContent() {
-        return RestResponse.success(PodTemplateParser.getInitPodTemplateContent());
+    public RestResponseBody<String> getInitContent() {
+        return RestResponseBody.success(PodTemplateParser.getInitPodTemplateContent());
     }
 
-    /** @param hosts hostname:ipv4,hostname:ipv4,hostname:ipv4... */
+    /** @param request hosts hostname:ipv4,hostname:ipv4,hostname:ipv4... */
     @PostMapping("comp_host_alias")
-    public RestResponse completeHostAlias(String hosts, String podTemplate) {
-        Map<String, String> hostMap = covertHostsParamToMap(hosts);
-        String completedPodTemplate = PodTemplateParser.completeHostAliasSpec(hostMap, podTemplate);
-        return RestResponse.success(completedPodTemplate);
+    public RestResponseBody<String> completeHostAlias(@Valid FlinkPodTemplateHostAliasRequest request) {
+        Map<String, String> hostMap = covertHostsParamToMap(request.getHosts());
+        String completedPodTemplate =
+            PodTemplateParser.completeHostAliasSpec(hostMap, request.getPodTemplate());
+        return RestResponseBody.success(completedPodTemplate);
     }
 
     private Map<String, String> covertHostsParamToMap(String hosts) {
@@ -79,19 +84,19 @@
     }
 
     @PostMapping("extract_host_alias")
-    public RestResponse extractHostAlias(String podTemplate) {
-        Map<String, String> hosts = PodTemplateParser.extractHostAliasMap(podTemplate);
+    public RestResponseBody<List<String>> extractHostAlias(@Valid FlinkPodTemplateExtractRequest request) {
+        Map<String, String> hosts = PodTemplateParser.extractHostAliasMap(request.getPodTemplate());
         List<String> friendlyHosts = hosts.entrySet().stream()
             .map(e -> e.getKey() + ":" + e.getValue())
             .collect(Collectors.toList());
-        return RestResponse.success(friendlyHosts);
+        return RestResponseBody.success(friendlyHosts);
     }
 
-    /** @param hosts hostname:ipv4,hostname:ipv4,hostname:ipv4... */
+    /** @param request hosts hostname:ipv4,hostname:ipv4,hostname:ipv4... */
     @PostMapping("preview_host_alias")
-    public RestResponse previewHostAlias(String hosts) {
-        Map<String, String> hostMap = covertHostsParamToMap(hosts);
+    public RestResponseBody<String> previewHostAlias(@Valid FlinkPodTemplatePreviewRequest request) {
+        Map<String, String> hostMap = covertHostsParamToMap(request.getHosts());
         String podTemplate = PodTemplateParser.previewHostAliasSpec(hostMap);
-        return RestResponse.success(podTemplate);
+        return RestResponseBody.success(podTemplate);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkSqlController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkSqlController.java
index ad08871..c21c9d8 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkSqlController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/FlinkSqlController.java
@@ -18,12 +18,21 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
-import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.assembler.FlinkSqlAssembler;
 import org.apache.streampark.console.core.entity.FlinkSql;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlCompleteRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlDeleteRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlGetRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlListQueryRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlVerifyRequest;
+import org.apache.streampark.console.core.response.flink.FlinkSqlResponse;
+import org.apache.streampark.console.core.response.sql.SqlCompleteResponse;
 import org.apache.streampark.console.core.service.FlinkSqlService;
 import org.apache.streampark.console.core.service.SqlCompleteService;
 import org.apache.streampark.console.core.service.VariableService;
@@ -39,7 +48,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.Valid;
 
 import java.util.List;
 
@@ -63,69 +72,73 @@
     private SqlCompleteService sqlComplete;
 
     @PostMapping("verify")
-    public RestResponse verify(String sql, Long versionId, Long teamId) {
-        sql = variableService.replaceVariable(teamId, sql);
-        FlinkSqlValidationResult flinkSqlValidationResult = flinkSqlService.verifySql(sql, versionId);
+    public RestResponseBody<Boolean> verify(@Valid FlinkSqlVerifyRequest request) {
+        String sql = variableService.replaceVariable(request.getTeamId(), request.getSql());
+        FlinkSqlValidationResult flinkSqlValidationResult =
+            flinkSqlService.verifySql(sql, request.getVersionId());
         if (!flinkSqlValidationResult.success()) {
-            // record error type, such as error sql, reason and error start/end line
             String exception = flinkSqlValidationResult.exception();
-            RestResponse response = RestResponse.success()
-                .data(false)
-                .message(exception)
-                .put(TYPE, flinkSqlValidationResult.failedType().getFailedType())
-                .put(START, flinkSqlValidationResult.lineStart())
-                .put(END, flinkSqlValidationResult.lineEnd());
-
+            RestResponseBody<Boolean> response = RestResponseBody.success(false).message(exception);
+            response.extra(TYPE, flinkSqlValidationResult.failedType().getFailedType());
+            response.extra(START, flinkSqlValidationResult.lineStart());
+            response.extra(END, flinkSqlValidationResult.lineEnd());
             if (flinkSqlValidationResult.errorLine() > 0) {
-                response
-                    .put(START, flinkSqlValidationResult.errorLine())
-                    .put(END, flinkSqlValidationResult.errorLine() + 1);
+                response.extra(START, flinkSqlValidationResult.errorLine());
+                response.extra(END, flinkSqlValidationResult.errorLine() + 1);
             }
             return response;
         }
-        return RestResponse.success(true);
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("list")
-    @Permission(app = "#flinkSql.appId", team = "#flinkSql.teamId")
-    public RestResponse list(FlinkSql flinkSql, RestRequest request) {
-        IPage<FlinkSql> page = flinkSqlService.getPage(flinkSql.getAppId(), request);
-        return RestResponse.success(page);
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<FlinkSqlResponse>> list(@Valid FlinkSqlListQueryRequest query, RestRequest request) {
+        IPage<FlinkSql> page = flinkSqlService.getPage(query.getAppId(), request);
+        return RestResponseBody.success(FlinkSqlAssembler.toPageResponse(page));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("sql:delete")
-    @Permission(app = "#flinkSql.appId", team = "#flinkSql.teamId")
-    public RestResponse delete(FlinkSql flinkSql) {
-        Boolean deleted = flinkSqlService.removeById(flinkSql.getSql());
-        return RestResponse.success(deleted);
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson FlinkSqlDeleteRequest request) {
+        Boolean deleted = flinkSqlService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
+    /** {@code data} is {@link FlinkSqlResponse} for one id, or {@link FlinkSqlResponse}{@code []} for two ids (legacy compare). */
+    @SuppressWarnings("java:S1452")
     @PostMapping("get")
-    @Permission(app = "#appId", team = "#teamId")
-    public RestResponse get(Long appId, Long teamId, String id) throws InternalException {
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<?> get(@Valid FlinkSqlGetRequest request) throws InternalException {
         ApiAlertException.throwIfTrue(
-            appId == null || teamId == null, "Permission denied, appId and teamId cannot be null");
-        String[] array = id.split(",");
+            request.getAppId() == null || request.getTeamId() == null,
+            "Permission denied, appId and teamId cannot be null");
+        String[] array = request.getId().split(",");
         FlinkSql flinkSql1 = flinkSqlService.getById(array[0]);
+        ApiAlertException.throwIfNull(flinkSql1, "Flink SQL not found.");
         flinkSql1.base64Encode();
         if (array.length == 1) {
-            return RestResponse.success(flinkSql1);
+            return RestResponseBody.success(FlinkSqlAssembler.toResponse(flinkSql1));
         }
         FlinkSql flinkSql2 = flinkSqlService.getById(array[1]);
+        ApiAlertException.throwIfNull(flinkSql2, "Flink SQL not found.");
         flinkSql2.base64Encode();
-        return RestResponse.success(new FlinkSql[]{flinkSql1, flinkSql2});
+        return RestResponseBody.success(
+            FlinkSqlAssembler.toArrayResponse(new FlinkSql[]{flinkSql1, flinkSql2}));
     }
 
     @PostMapping("history")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse history(FlinkApplication app) {
-        List<FlinkSql> sqlList = flinkSqlService.listFlinkSqlHistory(app.getId());
-        return RestResponse.success(sqlList);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<List<FlinkSqlResponse>> history(@Valid FlinkAppIdRequest request) {
+        List<FlinkSql> sqlList = flinkSqlService.listFlinkSqlHistory(request.getId());
+        return RestResponseBody.success(FlinkSqlAssembler.toListResponse(sqlList));
     }
 
     @PostMapping("sql_complete")
-    public RestResponse getSqlComplete(@NotNull(message = "{required}") String sql) {
-        return RestResponse.success().put("word", sqlComplete.getComplete(sql));
+    public RestResponseBody<SqlCompleteResponse> getSqlComplete(@Valid FlinkSqlCompleteRequest request) {
+        SqlCompleteResponse response = new SqlCompleteResponse();
+        response.setWord(sqlComplete.getComplete(request.getSql()));
+        return RestResponseBody.success(response);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/MessageController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/MessageController.java
index 490ff6b..8ff7397 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/MessageController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/MessageController.java
@@ -18,9 +18,14 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.MessageAssembler;
 import org.apache.streampark.console.core.entity.Message;
 import org.apache.streampark.console.core.enums.NoticeTypeEnum;
+import org.apache.streampark.console.core.request.message.MessageDeleteRequest;
+import org.apache.streampark.console.core.request.message.MessageNoticeRequest;
+import org.apache.streampark.console.core.response.message.MessageResponse;
 import org.apache.streampark.console.core.service.MessageService;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -31,6 +36,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 @Slf4j
 @Validated
 @RestController
@@ -41,14 +48,15 @@
     private MessageService messageService;
 
     @PostMapping("notice")
-    public RestResponse notice(Integer type, RestRequest request) {
-        NoticeTypeEnum noticeTypeEnum = NoticeTypeEnum.of(type);
-        IPage<Message> pages = messageService.getUnReadPage(noticeTypeEnum, request);
-        return RestResponse.success(pages);
+    public RestResponseBody<IPage<MessageResponse>> notice(@Valid MessageNoticeRequest request,
+                                                           RestRequest restRequest) {
+        NoticeTypeEnum noticeTypeEnum = NoticeTypeEnum.of(request.getType());
+        IPage<Message> pages = messageService.getUnReadPage(noticeTypeEnum, restRequest);
+        return RestResponseBody.success(MessageAssembler.toPageResponse(pages));
     }
 
     @PostMapping("delete")
-    public RestResponse delete(Long id) {
-        return RestResponse.success(messageService.removeById(id));
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson MessageDeleteRequest request) {
+        return RestResponseBody.success(messageService.removeById(request.getId()));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
index ede5b46..f8b7af9 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/OpenAPIController.java
@@ -17,12 +17,20 @@
 
 package org.apache.streampark.console.core.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.OpenAPI;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.FlinkApplicationAssembler;
+import org.apache.streampark.console.core.bean.ApiContractDocument;
 import org.apache.streampark.console.core.bean.OpenAPISchema;
+import org.apache.streampark.console.core.component.ApiContractExportService;
+import org.apache.streampark.console.core.component.ApiTypeScriptGenerator;
 import org.apache.streampark.console.core.component.OpenAPIComponent;
-import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.request.flink.FlinkAppCancelRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+import org.apache.streampark.console.core.request.flink.OpenAPICurlRequest;
+import org.apache.streampark.console.core.request.flink.OpenAPISchemaRequest;
 import org.apache.streampark.console.core.service.application.FlinkApplicationActionService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -33,8 +41,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
+import javax.validation.Valid;
 
 @Validated
 @RestController
@@ -45,6 +52,9 @@
     private OpenAPIComponent openAPIComponent;
 
     @Autowired
+    private ApiContractExportService apiContractExportService;
+
+    @Autowired
     private FlinkApplicationActionService applicationActionService;
 
     @OpenAPI(name = "flinkStart", header = {
@@ -57,12 +67,12 @@
             @OpenAPI.Param(name = "savepointPath", description = "savepoint or checkpoint path", required = false, type = String.class),
             @OpenAPI.Param(name = "allowNonRestored", description = "ignore savepoint if cannot be restored", required = false, type = Boolean.class, defaultValue = "false"),
     })
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("app/start")
     @RequiresPermissions("app:start")
-    public RestResponse flinkStart(FlinkApplication app) throws Exception {
-        applicationActionService.start(app, false);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> flinkStart(@Valid @FormOrJson FlinkAppStartRequest request) throws Exception {
+        applicationActionService.start(FlinkApplicationAssembler.toEntity(request), false);
+        return RestResponseBody.success(true);
     }
 
     @OpenAPI(name = "flinkCancel", header = {
@@ -74,27 +84,36 @@
             @OpenAPI.Param(name = "savepointPath", description = "savepoint path", required = false, type = String.class),
             @OpenAPI.Param(name = "drain", description = "send max watermark before canceling", required = false, type = Boolean.class, defaultValue = "false"),
     })
-    @Permission(app = "#app.id", team = "#app.teamId")
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("app/cancel")
     @RequiresPermissions("app:cancel")
-    public RestResponse flinkCancel(FlinkApplication app) throws Exception {
-        applicationActionService.cancel(app);
-        return RestResponse.success();
+    public RestResponseBody<Void> flinkCancel(@Valid @FormOrJson FlinkAppCancelRequest request) throws Exception {
+        applicationActionService.cancel(FlinkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("curl")
-    public RestResponse copyOpenApiCurl(String name,
-                                        String baseUrl,
-                                        @NotNull Long appId,
-                                        @NotNull Long teamId) {
-        String url = openAPIComponent.getOpenApiCUrl(name, baseUrl, appId, teamId);
-        return RestResponse.success(url);
+    public RestResponseBody<String> copyOpenApiCurl(OpenAPICurlRequest request) {
+        String url = openAPIComponent.getOpenApiCUrl(
+            request.getName(), request.getBaseUrl(), request.getAppId(), request.getTeamId());
+        return RestResponseBody.success(url);
     }
 
     @PostMapping("schema")
-    public RestResponse schema(@NotBlank(message = "{required}") String name) {
-        OpenAPISchema openAPISchema = openAPIComponent.getOpenAPISchema(name);
-        return RestResponse.success(openAPISchema);
+    public RestResponseBody<OpenAPISchema> schema(@Valid OpenAPISchemaRequest request) {
+        OpenAPISchema openAPISchema = openAPIComponent.getOpenAPISchema(request.getName());
+        return RestResponseBody.success(openAPISchema);
+    }
+
+    @PostMapping("contracts")
+    public RestResponseBody<ApiContractDocument> exportContracts() {
+        return RestResponseBody.success(apiContractExportService.exportContracts());
+    }
+
+    @PostMapping("contracts/typescript")
+    public RestResponseBody<String> exportTypeScript() {
+        ApiContractDocument document = apiContractExportService.exportContracts();
+        return RestResponseBody.success(ApiTypeScriptGenerator.generate(document));
     }
 
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ProjectController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ProjectController.java
index 1f09817..4b90aa7 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ProjectController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ProjectController.java
@@ -17,28 +17,44 @@
 
 package org.apache.streampark.console.core.controller;
 
+import org.apache.streampark.console.base.domain.ResponseCode;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.ApiAlertException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.AppChangeEvent;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.ProjectAssembler;
 import org.apache.streampark.console.core.entity.Project;
 import org.apache.streampark.console.core.enums.GitAuthorizedErrorEnum;
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.project.ProjectBuildLogRequest;
+import org.apache.streampark.console.core.request.project.ProjectCreateRequest;
+import org.apache.streampark.console.core.request.project.ProjectExistsRequest;
+import org.apache.streampark.console.core.request.project.ProjectGitRequest;
+import org.apache.streampark.console.core.request.project.ProjectListQueryRequest;
+import org.apache.streampark.console.core.request.project.ProjectModuleRequest;
+import org.apache.streampark.console.core.request.project.ProjectUpdateRequest;
+import org.apache.streampark.console.core.response.project.ProjectBranchesResponse;
+import org.apache.streampark.console.core.response.project.ProjectResponse;
 import org.apache.streampark.console.core.service.ProjectService;
+import org.apache.streampark.console.core.service.result.ProjectBuildLogResult;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -52,115 +68,129 @@
     private ProjectService projectService;
 
     @PostMapping("create")
-    @Permission(team = "#project.teamId")
+    @Permission(team = "#request.teamId")
     @RequiresPermissions("project:create")
-    public RestResponse create(Project project) {
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson ProjectCreateRequest request) {
         ApiAlertException.throwIfNull(
-            project.getTeamId(), "The teamId can't be null. Create team failed.");
-        return projectService.create(project);
+            request.getTeamId(), "The teamId can't be null. Create team failed.");
+        boolean status = projectService.create(ProjectAssembler.toEntity(request));
+        if (status) {
+            return RestResponseBody.success(true).message("Add project successfully");
+        }
+        return RestResponseBody.success(false).message("Add project failed");
     }
 
     @AppChangeEvent
     @PostMapping("update")
     @RequiresPermissions("project:update")
-    @Permission(team = "#project.teamId")
-    public RestResponse update(Project project) {
-        boolean update = projectService.update(project);
-        return RestResponse.success().data(update);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson ProjectUpdateRequest request) {
+        boolean update = projectService.update(ProjectAssembler.toEntity(request));
+        return RestResponseBody.success(update);
     }
 
     @PostMapping("get")
-    @Permission(team = "#project.teamId")
-    public RestResponse get(Project project) {
-        return RestResponse.success().data(projectService.getById(project.getId()));
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<ProjectResponse> get(@Valid TeamScopedIdRequest request) {
+        return RestResponseBody.success(ProjectAssembler.toResponse(projectService.getById(request.getId())));
     }
 
     @PostMapping("build")
     @RequiresPermissions("project:build")
-    @Permission(team = "#project.teamId")
-    public RestResponse build(Project project) throws Exception {
-        projectService.build(project.getId());
-        return RestResponse.success();
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<Void> build(@Valid @FormOrJson TeamScopedIdRequest request) throws Exception {
+        projectService.build(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("build_log")
     @RequiresPermissions("project:build")
-    @Permission(team = "#teamId")
-    public RestResponse buildLog(
-                                 Long id,
-                                 @RequestParam(value = "startOffset", required = false) Long startOffset) {
-        return projectService.getBuildLog(id, startOffset);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<String> buildLog(ProjectBuildLogRequest request) {
+        ProjectBuildLogResult result = projectService.getBuildLog(request.getId(), request.getStartOffset());
+        if (result.isFailed()) {
+            return RestResponseBody.fail(ResponseCode.CODE_FAIL, result.getContent());
+        }
+        RestResponseBody<String> response = RestResponseBody.success(result.getContent());
+        if (result.getOffset() != null) {
+            response.extra("offset", result.getOffset());
+        }
+        if (result.getReadFinished() != null) {
+            response.extra("readFinished", result.getReadFinished());
+        }
+        return response;
     }
 
     @PostMapping("list")
     @RequiresPermissions("project:view")
-    @Permission(team = "#project.teamId")
-    public RestResponse list(Project project, RestRequest restRequest) {
-        if (project.getTeamId() == null) {
-            return RestResponse.success(Collections.emptyList());
+    @Permission(team = "#query.teamId")
+    public RestResponseBody<IPage<ProjectResponse>> list(ProjectListQueryRequest query, RestRequest restRequest) {
+        if (query.getTeamId() == null) {
+            Page<ProjectResponse> emptyPage = new Page<>();
+            emptyPage.setRecords(Collections.emptyList());
+            return RestResponseBody.success(emptyPage);
         }
-        IPage<Project> page = projectService.getPage(project, restRequest);
-        return RestResponse.success().data(page);
+        IPage<Project> page = projectService.getPage(ProjectAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(ProjectAssembler.toPageResponse(page));
     }
 
     @PostMapping("branches")
-    @Permission(team = "#project.teamId")
-    public RestResponse branches(Project project) {
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<ProjectBranchesResponse> branches(ProjectGitRequest request) {
+        Project project = ProjectAssembler.toEntity(request);
         List<String> branches = projectService.getAllBranches(project);
         List<String> tags = projectService.getAllTags(project);
-        Map<String, List<String>> refs = new HashMap<>();
-        refs.put("tags", tags);
-        refs.put("branches", branches);
-        return RestResponse.success().data(refs);
+        return RestResponseBody.success(ProjectAssembler.toBranchesResponse(branches, tags));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("project:delete")
-    @Permission(team = "#project.teamId")
-    public RestResponse delete(Project project) {
-        Boolean deleted = projectService.removeById(project.getId());
-        return RestResponse.success().data(deleted);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson TeamScopedIdRequest request) {
+        Boolean deleted = projectService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("git_check")
-    @Permission(team = "#project.teamId")
-    public RestResponse gitCheck(Project project) {
-        GitAuthorizedErrorEnum error = projectService.gitCheck(project);
-        return RestResponse.success().data(error.getType());
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<Integer> gitCheck(ProjectGitRequest request) {
+        GitAuthorizedErrorEnum error = projectService.gitCheck(ProjectAssembler.toEntity(request));
+        return RestResponseBody.success(error.getType());
     }
 
     @PostMapping("exists")
-    @Permission(team = "#project.teamId")
-    public RestResponse exists(Project project) {
-        boolean exists = projectService.exists(project);
-        return RestResponse.success().data(exists);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<Boolean> exists(ProjectExistsRequest request) {
+        boolean exists = projectService.exists(ProjectAssembler.toEntity(request));
+        return RestResponseBody.success(exists);
     }
 
     @PostMapping("modules")
-    @Permission(team = "#project.teamId")
-    public RestResponse modules(Project project) {
-        List<String> result = projectService.listModules(project.getId());
-        return RestResponse.success().data(result);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<List<String>> modules(@Valid TeamScopedIdRequest request) {
+        List<String> result = projectService.listModules(request.getId());
+        return RestResponseBody.success(result);
     }
 
     @PostMapping("jars")
-    @Permission(team = "#project.teamId")
-    public RestResponse jars(Project project) {
-        List<String> result = projectService.listJars(project);
-        return RestResponse.success().data(result);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<List<String>> jars(ProjectModuleRequest request) {
+        List<String> result = projectService.listJars(ProjectAssembler.toEntity(request));
+        return RestResponseBody.success(result);
     }
 
     @PostMapping("list_conf")
-    @Permission(team = "#project.teamId")
-    public RestResponse listConf(Project project) {
-        List<Map<String, Object>> list = projectService.listConf(project);
-        return RestResponse.success().data(list);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<List<Map<String, Object>>> listConf(ProjectModuleRequest request) {
+        List<Map<String, Object>> list =
+            projectService.listConf(ProjectAssembler.toEntity(request));
+        return RestResponseBody.success(list);
     }
 
     @PostMapping("select")
-    @Permission(team = "#teamId")
-    public RestResponse select(@RequestParam Long teamId) {
-        List<Project> list = projectService.listByTeamId(teamId);
-        return RestResponse.success().data(list);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<List<ProjectResponse>> select(@Valid TeamIdRequest request) {
+        List<Project> list = projectService.listByTeamId(request.getTeamId());
+        return RestResponseBody.success(ProjectAssembler.toListResponse(list));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ResourceController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ResourceController.java
index 6be9b66..3053a55 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ResourceController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ResourceController.java
@@ -18,9 +18,18 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
-import org.apache.streampark.console.core.bean.UploadResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.ResourceAssembler;
 import org.apache.streampark.console.core.entity.Resource;
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.resource.ResourceCreateRequest;
+import org.apache.streampark.console.core.request.resource.ResourcePageQueryRequest;
+import org.apache.streampark.console.core.request.resource.ResourceUpdateRequest;
+import org.apache.streampark.console.core.response.resource.ResourceCheckResponse;
+import org.apache.streampark.console.core.response.resource.ResourceResponse;
+import org.apache.streampark.console.core.response.resource.ResourceUploadResponse;
 import org.apache.streampark.console.core.service.ResourceService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -33,12 +42,12 @@
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.validation.Valid;
 
+import java.io.IOException;
 import java.util.List;
 
 @Slf4j
@@ -52,53 +61,54 @@
 
     @PostMapping("add")
     @RequiresPermissions("resource:add")
-    public RestResponse addResource(@Valid Resource resource) throws Exception {
-        this.resourceService.addResource(resource);
-        return RestResponse.success();
+    public RestResponseBody<Void> addResource(@Valid @FormOrJson ResourceCreateRequest request) throws Exception {
+        this.resourceService.addResource(ResourceAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("check")
-    public RestResponse checkResource(@Valid Resource resource) throws Exception {
-        return this.resourceService.checkResource(resource);
+    public RestResponseBody<ResourceCheckResponse> checkResource(@Valid ResourceCreateRequest request) throws Exception {
+        return RestResponseBody.success(
+            ResourceAssembler.toCheckResponse(resourceService.checkResource(ResourceAssembler.toEntity(request))));
     }
 
     @PostMapping("page")
-    public RestResponse page(RestRequest restRequest, Resource resource) {
-        IPage<Resource> page = resourceService.getPage(resource, restRequest);
-        return RestResponse.success(page);
+    public RestResponseBody<IPage<ResourceResponse>> page(RestRequest restRequest, ResourcePageQueryRequest query) {
+        IPage<Resource> page =
+            resourceService.getPage(ResourceAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(ResourceAssembler.toPageResponse(page));
     }
 
     @PutMapping("update")
     @RequiresPermissions("resource:update")
-    public RestResponse updateResource(@Valid Resource resource) {
-        resourceService.updateResource(resource);
-        return RestResponse.success();
+    public RestResponseBody<Void> updateResource(@Valid @FormOrJson ResourceUpdateRequest request) {
+        resourceService.updateResource(ResourceAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("delete")
     @RequiresPermissions("resource:delete")
-    public RestResponse deleteResource(@Valid Resource resource) {
-        this.resourceService.remove(resource.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> deleteResource(@Valid @FormOrJson TeamScopedIdRequest request) {
+        this.resourceService.remove(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("list")
-    public RestResponse listResource(@RequestParam Long teamId) {
-        List<Resource> resourceList = resourceService.listByTeamId(teamId);
-        return RestResponse.success(resourceList);
+    public RestResponseBody<List<ResourceResponse>> listResource(TeamIdRequest request) {
+        List<Resource> resourceList = resourceService.listByTeamId(request.getTeamId());
+        return RestResponseBody.success(ResourceAssembler.toListResponse(resourceList));
     }
 
     @PostMapping("upload")
     @RequiresPermissions("resource:add")
-    public RestResponse upload(MultipartFile file) throws Exception {
-        UploadResponse uploadPath = resourceService.upload(file);
-        return RestResponse.success(uploadPath);
+    public RestResponseBody<ResourceUploadResponse> upload(MultipartFile file) throws IOException {
+        return RestResponseBody.success(ResourceAssembler.toUploadResponse(resourceService.upload(file)));
     }
 
     @PostMapping("upload_jars")
-    public RestResponse listUploadJars() {
+    public RestResponseBody<List<String>> listUploadJars() {
         List<String> jars = resourceService.listHistoryUploadJars();
-        return RestResponse.success(jars);
+        return RestResponseBody.success(jars);
     }
 
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SavepointController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SavepointController.java
index 8b7921e..7017845 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SavepointController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SavepointController.java
@@ -18,11 +18,17 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.SavepointAssembler;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.entity.FlinkSavepoint;
+import org.apache.streampark.console.core.request.flink.SavepointDeleteRequest;
+import org.apache.streampark.console.core.request.flink.SavepointHistoryQueryRequest;
+import org.apache.streampark.console.core.request.flink.SavepointTriggerRequest;
+import org.apache.streampark.console.core.response.flink.SavepointResponse;
 import org.apache.streampark.console.core.service.SavepointService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationManageService;
 
@@ -36,7 +42,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.annotation.Nullable;
+import javax.validation.Valid;
 
 @Slf4j
 @Validated
@@ -51,28 +57,28 @@
     private SavepointService savepointService;
 
     @PostMapping("history")
-    @Permission(app = "#sp.appId", team = "#sp.teamId")
-    public RestResponse history(FlinkSavepoint sp, RestRequest request) {
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<SavepointResponse>> history(SavepointHistoryQueryRequest query, RestRequest request) {
+        FlinkSavepoint sp = SavepointAssembler.toEntity(query);
         IPage<FlinkSavepoint> page = savepointService.getPage(sp, request);
-        return RestResponse.success(page);
+        return RestResponseBody.success(SavepointAssembler.toPageResponse(page));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("savepoint:delete")
-    @Permission(app = "#sp.appId", team = "#sp.teamId")
-    public RestResponse delete(FlinkSavepoint sp) throws InternalException {
-        FlinkSavepoint savepoint = savepointService.getById(sp.getId());
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson SavepointDeleteRequest request) throws InternalException {
+        FlinkSavepoint savepoint = savepointService.getById(request.getId());
         FlinkApplication application = applicationManageService.getById(savepoint.getAppId());
-        Boolean deleted = savepointService.remove(sp.getId(), application);
-        return RestResponse.success(deleted);
+        Boolean deleted = savepointService.remove(request.getId(), application);
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("trigger")
-    @Permission(app = "#savepoint.appId", team = "#savepoint.teamId")
+    @Permission(app = "#request.appId", team = "#request.teamId")
     @RequiresPermissions("savepoint:trigger")
-    public RestResponse trigger(
-                                Long appId, @Nullable String savepointPath, @Nullable Boolean nativeFormat) {
-        savepointService.trigger(appId, savepointPath, nativeFormat);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> trigger(@Valid @FormOrJson SavepointTriggerRequest request) {
+        savepointService.trigger(request.getAppId(), request.getSavepointPath(), request.getNativeFormat());
+        return RestResponseBody.success(true);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SettingController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SettingController.java
index 4b3c751..4dc27ed 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SettingController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SettingController.java
@@ -18,11 +18,18 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.common.util.HadoopUtils;
-import org.apache.streampark.console.base.domain.RestResponse;
-import org.apache.streampark.console.core.bean.DockerConfig;
-import org.apache.streampark.console.core.bean.ResponseResult;
-import org.apache.streampark.console.core.bean.SenderEmail;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.SettingAssembler;
 import org.apache.streampark.console.core.entity.Setting;
+import org.apache.streampark.console.core.request.setting.SettingDockerRequest;
+import org.apache.streampark.console.core.request.setting.SettingEmailRequest;
+import org.apache.streampark.console.core.request.setting.SettingGetRequest;
+import org.apache.streampark.console.core.request.setting.SettingUpdateRequest;
+import org.apache.streampark.console.core.response.setting.SettingCheckResponse;
+import org.apache.streampark.console.core.response.setting.SettingDockerResponse;
+import org.apache.streampark.console.core.response.setting.SettingEmailResponse;
+import org.apache.streampark.console.core.response.setting.SettingResponse;
 import org.apache.streampark.console.core.service.SettingService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -35,6 +42,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.io.IOException;
 import java.util.List;
 
@@ -49,70 +58,72 @@
 
     @PostMapping("all")
     @RequiresPermissions("setting:view")
-    public RestResponse all() {
-        LambdaQueryWrapper<Setting> query = new LambdaQueryWrapper<Setting>().orderByAsc(Setting::getOrderNum);
+    public RestResponseBody<List<SettingResponse>> all() {
+        LambdaQueryWrapper<Setting> query =
+            new LambdaQueryWrapper<Setting>().orderByAsc(Setting::getOrderNum);
         List<Setting> setting = settingService.list(query);
-        return RestResponse.success(setting);
+        return RestResponseBody.success(SettingAssembler.toListResponse(setting));
     }
 
     @PostMapping("get")
-    public RestResponse get(String key) {
-        Setting setting = settingService.get(key);
-        return RestResponse.success(setting);
+    public RestResponseBody<SettingResponse> get(@Valid SettingGetRequest request) {
+        Setting setting = settingService.get(request.getKey());
+        return RestResponseBody.success(SettingAssembler.toResponse(setting));
     }
 
     @PostMapping("update")
     @RequiresPermissions("setting:update")
-    public RestResponse update(Setting setting) {
-        boolean updated = settingService.update(setting);
-        return RestResponse.success(updated);
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson SettingUpdateRequest request) {
+        boolean updated = settingService.update(SettingAssembler.toEntity(request));
+        return RestResponseBody.success(updated);
     }
 
     @PostMapping("docker")
     @RequiresPermissions("setting:view")
-    public RestResponse docker() {
-        DockerConfig dockerConfig = settingService.getDockerConfig();
-        return RestResponse.success(dockerConfig);
+    public RestResponseBody<SettingDockerResponse> docker() {
+        return RestResponseBody.success(SettingAssembler.toDockerResponse(settingService.getDockerConfig()));
     }
 
     @PostMapping("check/docker")
     @RequiresPermissions("setting:view")
-    public RestResponse checkDocker(DockerConfig dockerConfig) {
-        ResponseResult result = settingService.checkDocker(dockerConfig);
-        return RestResponse.success(result);
+    public RestResponseBody<SettingCheckResponse> checkDocker(@Valid SettingDockerRequest request) {
+        return RestResponseBody.success(
+            SettingAssembler.toCheckResponse(
+                settingService.checkDocker(SettingAssembler.toDockerConfig(request))));
     }
 
     @PostMapping("update/docker")
     @RequiresPermissions("setting:update")
-    public RestResponse updateDocker(DockerConfig dockerConfig) {
-        boolean updated = settingService.updateDocker(dockerConfig);
-        return RestResponse.success(updated);
+    public RestResponseBody<Boolean> updateDocker(@Valid @FormOrJson SettingDockerRequest request) {
+        boolean updated =
+            settingService.updateDocker(SettingAssembler.toDockerConfig(request));
+        return RestResponseBody.success(updated);
     }
 
     @PostMapping("email")
     @RequiresPermissions("setting:view")
-    public RestResponse email() {
-        SenderEmail senderEmail = settingService.getSenderEmail();
-        return RestResponse.success(senderEmail);
+    public RestResponseBody<SettingEmailResponse> email() {
+        return RestResponseBody.success(SettingAssembler.toEmailResponse(settingService.getSenderEmail()));
     }
 
     @PostMapping("check/email")
     @RequiresPermissions("setting:view")
-    public RestResponse checkEmail(SenderEmail senderEmail) {
-        ResponseResult result = settingService.checkEmail(senderEmail);
-        return RestResponse.success(result);
+    public RestResponseBody<SettingCheckResponse> checkEmail(@Valid SettingEmailRequest request) {
+        return RestResponseBody.success(
+            SettingAssembler.toCheckResponse(
+                settingService.checkEmail(SettingAssembler.toSenderEmail(request))));
     }
 
     @PostMapping("update/email")
     @RequiresPermissions("setting:update")
-    public RestResponse updateEmail(SenderEmail senderEmail) {
-        boolean updated = settingService.updateEmail(senderEmail);
-        return RestResponse.success(updated);
+    public RestResponseBody<Boolean> updateEmail(@Valid @FormOrJson SettingEmailRequest request) {
+        boolean updated = settingService.updateEmail(SettingAssembler.toSenderEmail(request));
+        return RestResponseBody.success(updated);
     }
 
     @PostMapping("check/hadoop")
-    public RestResponse checkHadoop() throws IOException {
+    public RestResponseBody<Boolean> checkHadoop() throws IOException {
         HadoopUtils.hdfs().getStatus();
-        return RestResponse.success(true);
+        return RestResponseBody.success(true);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java
index 0d9e87d..1119f35 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java
@@ -20,13 +20,34 @@
 import org.apache.streampark.common.util.Utils;
 import org.apache.streampark.common.util.YarnUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.AppChangeEvent;
-import org.apache.streampark.console.core.entity.ApplicationLog;
-import org.apache.streampark.console.core.entity.FlinkApplicationBackup;
+import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.AppLogAssembler;
+import org.apache.streampark.console.core.assembler.SparkApplicationAssembler;
 import org.apache.streampark.console.core.entity.SparkApplication;
 import org.apache.streampark.console.core.enums.AppExistsStateEnum;
+import org.apache.streampark.console.core.request.app.AppBackupDeleteRequest;
+import org.apache.streampark.console.core.request.app.AppBackupQueryRequest;
+import org.apache.streampark.console.core.request.app.AppOptLogQueryRequest;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCancelRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCheckNameRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppConfigRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCopyRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppCreateRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppIdRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppListQueryRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppMappingRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppStartRequest;
+import org.apache.streampark.console.core.request.spark.SparkAppUpdateRequest;
+import org.apache.streampark.console.core.response.app.AppBackupResponse;
+import org.apache.streampark.console.core.response.app.AppOptLogResponse;
+import org.apache.streampark.console.core.response.spark.SparkAppDashboardResponse;
+import org.apache.streampark.console.core.response.spark.SparkAppResponse;
 import org.apache.streampark.console.core.service.ResourceService;
 import org.apache.streampark.console.core.service.application.ApplicationLogService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationBackupService;
@@ -44,6 +65,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
@@ -75,175 +98,197 @@
     private ResourceService resourceService;
 
     @PostMapping("get")
+    @Permission(app = "#request.id")
     @RequiresPermissions("app:detail")
-    public RestResponse get(SparkApplication app) {
-        SparkApplication application = applicationManageService.getApp(app.getId());
-        return RestResponse.success(application);
+    public RestResponseBody<SparkAppResponse> get(@Valid SparkAppIdRequest request) {
+        SparkApplication application = applicationManageService.getApp(request.getId());
+        SparkAppResponse response = SparkApplicationAssembler.toResponse(application);
+        return RestResponseBody.success(response);
     }
 
+    @Permission(team = "#request.teamId")
     @PostMapping("create")
     @RequiresPermissions("app:create")
-    public RestResponse create(SparkApplication app) throws IOException {
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson SparkAppCreateRequest request) throws IOException {
+        SparkApplication app = SparkApplicationAssembler.toEntity(request);
         boolean saved = applicationManageService.create(app);
-        return RestResponse.success(saved);
+        return RestResponseBody.success(saved);
     }
 
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("copy")
     @RequiresPermissions("app:copy")
-    public RestResponse copy(SparkApplication app) throws IOException {
-        applicationManageService.copy(app);
-        return RestResponse.success();
+    public RestResponseBody<Void> copy(@Valid @FormOrJson SparkAppCopyRequest request) throws IOException {
+        applicationManageService.copy(SparkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @AppChangeEvent
+    @Permission(app = "#request.id")
     @PostMapping("update")
     @RequiresPermissions("app:update")
-    public RestResponse update(SparkApplication app) {
-        applicationManageService.update(app);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson SparkAppUpdateRequest request) {
+        applicationManageService.update(SparkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("dashboard")
-    public RestResponse dashboard(Long teamId) {
-        Map<String, Serializable> dashboardMap = applicationInfoService.getDashboardDataMap(teamId);
-        return RestResponse.success(dashboardMap);
+    @Permission(team = "#request.teamId")
+    public RestResponseBody<SparkAppDashboardResponse> dashboard(@Valid TeamIdRequest request) {
+        Map<String, Serializable> dashboardMap = applicationInfoService.getDashboardDataMap(request.getTeamId());
+        return RestResponseBody.success(SparkApplicationAssembler.toDashboardResponse(dashboardMap));
     }
 
     @PostMapping("list")
+    @Permission(team = "#query.teamId")
     @RequiresPermissions("app:view")
-    public RestResponse list(SparkApplication app, RestRequest request) {
-        IPage<SparkApplication> applicationList = applicationManageService.page(app, request);
-        return RestResponse.success(applicationList);
+    public RestResponseBody<IPage<SparkAppResponse>> list(@Valid SparkAppListQueryRequest query, RestRequest request) {
+        SparkApplication appParam = SparkApplicationAssembler.toEntity(query);
+        IPage<SparkApplication> applicationList = applicationManageService.page(appParam, request);
+        return RestResponseBody.success(SparkApplicationAssembler.toPageResponse(applicationList));
     }
 
     @AppChangeEvent
     @PostMapping("mapping")
+    @Permission(app = "#request.id")
     @RequiresPermissions("app:mapping")
-    public RestResponse mapping(SparkApplication app) {
-        boolean flag = applicationManageService.mapping(app);
-        return RestResponse.success(flag);
+    public RestResponseBody<Boolean> mapping(@Valid @FormOrJson SparkAppMappingRequest request) {
+        boolean flag = applicationManageService.mapping(SparkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(flag);
     }
 
     @AppChangeEvent
+    @Permission(app = "#request.id")
     @PostMapping("revoke")
     @RequiresPermissions("app:release")
-    public RestResponse revoke(SparkApplication app) {
-        applicationActionService.revoke(app.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> revoke(@Valid @FormOrJson SparkAppIdRequest request) {
+        applicationActionService.revoke(request.getId());
+        return RestResponseBody.success();
     }
 
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("check/start")
     @RequiresPermissions("app:start")
-    public RestResponse checkStart(SparkApplication app) {
-        AppExistsStateEnum stateEnum = applicationInfoService.checkStart(app.getId());
-        return RestResponse.success(stateEnum.get());
+    public RestResponseBody<Integer> checkStart(@Valid SparkAppIdRequest request) {
+        AppExistsStateEnum stateEnum = applicationInfoService.checkStart(request.getId());
+        return RestResponseBody.success(stateEnum.get());
     }
 
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("start")
     @RequiresPermissions("app:start")
-    public RestResponse start(SparkApplication app) {
+    public RestResponseBody<Boolean> start(@Valid @FormOrJson SparkAppStartRequest request) {
         try {
-            applicationActionService.start(app, false);
-            return RestResponse.success(true);
+            applicationActionService.start(SparkApplicationAssembler.toEntity(request), false);
+            return RestResponseBody.success(true);
         } catch (Exception e) {
-            return RestResponse.success(false).message(e.getMessage());
+            return RestResponseBody.success(false).message(e.getMessage());
         }
     }
 
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("cancel")
     @RequiresPermissions("app:cancel")
-    public RestResponse cancel(SparkApplication app) throws Exception {
-        applicationActionService.cancel(app);
-        return RestResponse.success();
+    public RestResponseBody<Void> cancel(@Valid @FormOrJson SparkAppCancelRequest request) throws Exception {
+        applicationActionService.cancel(SparkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @AppChangeEvent
+    @Permission(app = "#request.id")
     @PostMapping("clean")
     @RequiresPermissions("app:clean")
-    public RestResponse clean(SparkApplication app) {
-        applicationManageService.clean(app);
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> clean(@Valid @FormOrJson SparkAppIdRequest request) {
+        applicationManageService.clean(SparkApplicationAssembler.toCleanEntity(request));
+        return RestResponseBody.success(true);
     }
 
+    @Permission(app = "#request.id")
     @PostMapping("forcedStop")
     @RequiresPermissions("app:cancel")
-    public RestResponse forcedStop(SparkApplication app) {
-        applicationActionService.forcedStop(app.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> forcedStop(@Valid @FormOrJson SparkAppIdRequest request) {
+        applicationActionService.forcedStop(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("yarn")
-    public RestResponse yarn() {
-        return RestResponse.success(YarnUtils.getRMWebAppProxyURL());
+    public RestResponseBody<String> yarn() {
+        return RestResponseBody.success(YarnUtils.getRMWebAppProxyURL());
     }
 
     @PostMapping("name")
-    public RestResponse yarnName(SparkApplication app) {
-        String yarnName = applicationInfoService.getYarnName(app.getConfig());
-        return RestResponse.success(yarnName);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<String> yarnName(SparkAppConfigRequest request) {
+        String yarnName = applicationInfoService.getYarnName(request.getConfig());
+        return RestResponseBody.success(yarnName);
     }
 
     @PostMapping("check/name")
-    public RestResponse checkName(SparkApplication app) {
-        AppExistsStateEnum exists = applicationInfoService.checkExists(app);
-        return RestResponse.success(exists.get());
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<Integer> checkName(@Valid SparkAppCheckNameRequest request) {
+        AppExistsStateEnum exists = applicationInfoService.checkExists(SparkApplicationAssembler.toEntity(request));
+        return RestResponseBody.success(exists.get());
     }
 
     @PostMapping("read_conf")
-    public RestResponse readConf(SparkApplication app) throws IOException {
-        String config = applicationInfoService.readConf(app.getConfig());
-        return RestResponse.success(config);
+    public RestResponseBody<String> readConf(SparkAppConfigRequest request) throws IOException {
+        String config = applicationInfoService.readConf(request.getConfig());
+        return RestResponseBody.success(config);
     }
 
     @PostMapping("backups")
-    public RestResponse backups(FlinkApplicationBackup backUp, RestRequest request) {
-        IPage<FlinkApplicationBackup> backups = backUpService.getPage(backUp, request);
-        return RestResponse.success(backups);
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<AppBackupResponse>> backups(AppBackupQueryRequest query, RestRequest request) {
+        return RestResponseBody.success(
+            AppLogAssembler.toBackupPage(backUpService.getPage(AppLogAssembler.toEntity(query), request)));
     }
 
     @PostMapping("opt_log")
-    public RestResponse optionlog(ApplicationLog applicationLog, RestRequest request) {
-        IPage<ApplicationLog> applicationList = applicationLogService.getPage(applicationLog, request);
-        return RestResponse.success(applicationList);
+    @Permission(app = "#query.appId", team = "#query.teamId")
+    public RestResponseBody<IPage<AppOptLogResponse>> optionlog(AppOptLogQueryRequest query, RestRequest request) {
+        return RestResponseBody.success(
+            AppLogAssembler.toOptLogPage(applicationLogService.getPage(AppLogAssembler.toEntity(query), request)));
     }
 
     @PostMapping("delete/opt_log")
     @RequiresPermissions("app:delete")
-    public RestResponse deleteOperationLog(Long id) {
-        Boolean deleted = applicationLogService.removeById(id);
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> deleteOperationLog(@Valid @FormOrJson IdRequest request) {
+        Boolean deleted = applicationLogService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
+    @Permission(app = "#request.id", team = "#request.teamId")
     @PostMapping("delete")
     @RequiresPermissions("app:delete")
-    public RestResponse delete(SparkApplication app) throws InternalException {
-        Boolean deleted = applicationManageService.remove(app.getId());
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson SparkAppIdRequest request) throws InternalException {
+        Boolean deleted = applicationManageService.remove(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
+    @Permission(app = "#request.appId")
     @PostMapping("delete/bak")
-    public RestResponse deleteBak(FlinkApplicationBackup backUp) throws InternalException {
-        Boolean deleted = backUpService.removeById(backUp.getId());
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> deleteBak(@Valid @FormOrJson AppBackupDeleteRequest request) throws InternalException {
+        Boolean deleted = backUpService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("check/jar")
-    public RestResponse checkjar(String jar) {
+    public RestResponseBody<Boolean> checkjar(String jar) {
         File file = new File(jar);
         try {
             Utils.requireCheckJarFile(file.toURI().toURL());
-            return RestResponse.success(true);
+            return RestResponseBody.success(true);
         } catch (IOException e) {
-            return RestResponse.success(file).message(e.getLocalizedMessage());
+            return RestResponseBody.success(false).message(e.getLocalizedMessage());
         }
     }
 
     @PostMapping("verify_schema")
-    public RestResponse verifySchema(String path) {
+    public RestResponseBody<Boolean> verifySchema(String path) {
         final URI uri = URI.create(path);
         final String scheme = uri.getScheme();
         final String pathPart = uri.getPath();
-        RestResponse restResponse = RestResponse.success(true);
+        RestResponseBody<Boolean> restResponse = RestResponseBody.success(true);
         String error = null;
         if (scheme == null) {
             error =
@@ -255,7 +300,7 @@
             error = "Cannot use the root directory for checkpoints.";
         }
         if (error != null) {
-            restResponse = RestResponse.success(false).message(error);
+            restResponse = RestResponseBody.success(false).message(error);
         }
         return restResponse;
     }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkConfigController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkConfigController.java
index 7d76ca3..2154820 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkConfigController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkConfigController.java
@@ -19,9 +19,16 @@
 
 import org.apache.streampark.common.util.HadoopConfigUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
-import org.apache.streampark.console.core.entity.SparkApplication;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.FlinkConfAssembler;
+import org.apache.streampark.console.core.assembler.SparkConfigAssembler;
 import org.apache.streampark.console.core.entity.SparkApplicationConfig;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.spark.SparkConfHistoryRequest;
+import org.apache.streampark.console.core.request.spark.SparkConfListQueryRequest;
+import org.apache.streampark.console.core.response.flink.FlinkConfHadoopResponse;
+import org.apache.streampark.console.core.response.spark.SparkConfResponse;
 import org.apache.streampark.console.core.service.application.SparkApplicationConfigService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -35,6 +42,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 import java.util.List;
 import java.util.Map;
 
@@ -48,42 +57,43 @@
     private SparkApplicationConfigService applicationConfigService;
 
     @PostMapping("get")
-    public RestResponse get(Long id) {
-        SparkApplicationConfig config = applicationConfigService.get(id);
-        return RestResponse.success(config);
+    public RestResponseBody<SparkConfResponse> get(@Valid IdRequest request) {
+        SparkApplicationConfig config = applicationConfigService.get(request.getId());
+        return RestResponseBody.success(SparkConfigAssembler.toResponse(config));
     }
 
     @PostMapping("template")
-    public RestResponse template() {
+    public RestResponseBody<String> template() {
         String config = applicationConfigService.readTemplate();
-        return RestResponse.success(config);
+        return RestResponseBody.success(config);
     }
 
     @PostMapping("list")
-    public RestResponse list(SparkApplicationConfig config, RestRequest request) {
-        IPage<SparkApplicationConfig> page = applicationConfigService.getPage(config, request);
-        return RestResponse.success(page);
+    public RestResponseBody<IPage<SparkConfResponse>> list(SparkConfListQueryRequest query, RestRequest request) {
+        SparkApplicationConfig configParam = SparkConfigAssembler.toEntity(query);
+        IPage<SparkApplicationConfig> page = applicationConfigService.getPage(configParam, request);
+        return RestResponseBody.success(SparkConfigAssembler.toPageResponse(page));
     }
 
     @PostMapping("history")
-    public RestResponse history(SparkApplication application) {
-        List<SparkApplicationConfig> history = applicationConfigService.list(application.getId());
-        return RestResponse.success(history);
+    public RestResponseBody<List<SparkConfResponse>> history(@Valid SparkConfHistoryRequest request) {
+        List<SparkApplicationConfig> history = applicationConfigService.list(request.getId());
+        return RestResponseBody.success(SparkConfigAssembler.toListResponse(history));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("conf:delete")
-    public RestResponse delete(Long id) {
-        Boolean deleted = applicationConfigService.removeById(id);
-        return RestResponse.success(deleted);
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson IdRequest request) {
+        Boolean deleted = applicationConfigService.removeById(request.getId());
+        return RestResponseBody.success(deleted);
     }
 
     @PostMapping("sysHadoopConf")
     @RequiresPermissions("app:create")
-    public RestResponse getSystemHadoopConfig() {
+    public RestResponseBody<FlinkConfHadoopResponse> getSystemHadoopConfig() {
         Map<String, Map<String, String>> result = ImmutableMap.of(
             "hadoop", HadoopConfigUtils.readSystemHadoopConf(),
             "hive", HadoopConfigUtils.readSystemHiveConf());
-        return RestResponse.success(result);
+        return RestResponseBody.success(FlinkConfAssembler.toHadoopResponse(result));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkEnvController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkEnvController.java
index b18fafa..8ab9a8f 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkEnvController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkEnvController.java
@@ -17,10 +17,19 @@
 
 package org.apache.streampark.console.core.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.exception.ApiDetailException;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.SparkEnvAssembler;
 import org.apache.streampark.console.core.entity.SparkEnv;
 import org.apache.streampark.console.core.enums.FlinkEnvCheckEnum;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvCheckRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvCreateRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvUpdateRequest;
+import org.apache.streampark.console.core.request.spark.SparkEnvValidityRequest;
+import org.apache.streampark.console.core.response.spark.SparkEnvResponse;
 import org.apache.streampark.console.core.service.SparkEnvService;
 
 import lombok.extern.slf4j.Slf4j;
@@ -30,6 +39,9 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
+import java.io.IOException;
 import java.util.List;
 
 @Slf4j
@@ -42,65 +54,63 @@
     private SparkEnvService sparkEnvService;
 
     @PostMapping("list")
-    public RestResponse list() {
+    public RestResponseBody<List<SparkEnvResponse>> list() {
         List<SparkEnv> sparkEnvList = sparkEnvService.list();
-        return RestResponse.success(sparkEnvList);
+        return RestResponseBody.success(SparkEnvAssembler.toListResponse(sparkEnvList));
     }
 
     @PostMapping("check")
-    public RestResponse check(SparkEnv version) {
-        FlinkEnvCheckEnum checkResp = sparkEnvService.check(version);
-        return RestResponse.success(checkResp.getCode());
+    public RestResponseBody<Integer> check(SparkEnvCheckRequest request) {
+        FlinkEnvCheckEnum checkResp = sparkEnvService.check(SparkEnvAssembler.toEntity(request));
+        return RestResponseBody.success(checkResp.getCode());
     }
 
     @PostMapping("create")
-    public RestResponse create(SparkEnv version) {
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson SparkEnvCreateRequest request) {
         try {
-            sparkEnvService.create(version);
+            sparkEnvService.create(SparkEnvAssembler.toEntity(request));
         } catch (Exception e) {
             throw new ApiDetailException(e);
         }
-        return RestResponse.success(true);
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("get")
-    public RestResponse get(Long id) throws Exception {
-        SparkEnv sparkEnv = sparkEnvService.getById(id);
+    public RestResponseBody<SparkEnvResponse> get(@Valid IdRequest request) throws Exception {
+        SparkEnv sparkEnv = sparkEnvService.getById(request.getId());
+        ApiAlertException.throwIfNull(sparkEnv, "Spark environment not found.");
         sparkEnv.unzipSparkConf();
-        return RestResponse.success(sparkEnv);
+        SparkEnvResponse response = SparkEnvAssembler.toResponse(sparkEnv);
+        return RestResponseBody.success(response);
     }
 
     @PostMapping("sync")
-    public RestResponse sync(Long id) throws Exception {
-        sparkEnvService.syncConf(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> sync(@Valid @FormOrJson IdRequest request) throws Exception {
+        sparkEnvService.syncConf(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("update")
-    public RestResponse update(SparkEnv version) throws Exception {
-        try {
-            sparkEnvService.update(version);
-        } catch (Exception e) {
-            throw new ApiDetailException(e);
-        }
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> update(@Valid @FormOrJson SparkEnvUpdateRequest request) throws IOException {
+        sparkEnvService.update(SparkEnvAssembler.toEntity(request));
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("delete")
-    public RestResponse delete(Long id) {
-        sparkEnvService.removeById(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson IdRequest request) {
+        sparkEnvService.removeById(request.getId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("validity")
-    public RestResponse validity(SparkEnv version) {
-        sparkEnvService.validity(version.getId());
-        return RestResponse.success(true);
+    public RestResponseBody<Boolean> validity(@Valid SparkEnvValidityRequest request) {
+        sparkEnvService.validity(request.getId());
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("default")
-    public RestResponse setDefault(Long id) {
-        sparkEnvService.setDefault(id);
-        return RestResponse.success();
+    public RestResponseBody<Void> setDefault(@Valid @FormOrJson IdRequest request) {
+        sparkEnvService.setDefault(request.getId());
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkPipelineController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkPipelineController.java
index a04fbc0..e9cc361 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkPipelineController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkPipelineController.java
@@ -17,9 +17,14 @@
 
 package org.apache.streampark.console.core.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.core.assembler.SparkPipelineAssembler;
 import org.apache.streampark.console.core.entity.ApplicationBuildPipeline;
+import org.apache.streampark.console.core.request.spark.SparkPipelineBuildRequest;
+import org.apache.streampark.console.core.request.spark.SparkPipelineDetailRequest;
+import org.apache.streampark.console.core.response.spark.SparkPipelineDetailResponse;
 import org.apache.streampark.console.core.service.application.SparkAplicationBuildPipelineService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -31,8 +36,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.HashMap;
-import java.util.Map;
+import javax.validation.Valid;
+
 import java.util.Optional;
 
 @Slf4j
@@ -47,35 +52,33 @@
     /**
      * Release application building pipeline.
      *
-     * @param appId application id
-     * @param forceBuild forced start pipeline or not
+     * @param request build request carrying application id and force flag
      * @return Whether the pipeline was successfully started
      */
     @PostMapping("build")
     @RequiresPermissions("app:create")
-    @Permission(app = "#appId")
-    public RestResponse buildApplication(Long appId, boolean forceBuild) {
+    @Permission(app = "#request.appId")
+    public RestResponseBody<Boolean> buildApplication(@Valid @FormOrJson SparkPipelineBuildRequest request) {
         try {
-            boolean actionResult = appBuildPipeService.buildApplication(appId, forceBuild);
-            return RestResponse.success(actionResult);
+            boolean actionResult = appBuildPipeService.buildApplication(request.getAppId(), request.isForceBuild());
+            return RestResponseBody.success(actionResult);
         } catch (Exception e) {
-            return RestResponse.success(false).message(e.getMessage());
+            return RestResponseBody.success(false).message(e.getMessage());
         }
     }
 
     /**
      * Get application building pipeline progress detail.
      *
-     * @param appId application id
-     * @return "pipeline" -> pipeline details, "docker" -> docker resolved snapshot
+     * @param request detail request carrying application id
+     * @return pipeline progress view
      */
     @PostMapping("/detail")
     @RequiresPermissions("app:view")
-    @Permission(app = "#appId")
-    public RestResponse getBuildProgressDetail(Long appId) {
-        Map<String, Object> details = new HashMap<>(0);
-        Optional<ApplicationBuildPipeline> pipeline = appBuildPipeService.getCurrentBuildPipeline(appId);
-        details.put("pipeline", pipeline.map(ApplicationBuildPipeline::toView).orElse(null));
-        return RestResponse.success(details);
+    @Permission(app = "#request.appId")
+    public RestResponseBody<SparkPipelineDetailResponse> getBuildProgressDetail(@Valid SparkPipelineDetailRequest request) {
+        Optional<ApplicationBuildPipeline> pipeline = appBuildPipeService.getCurrentBuildPipeline(request.getAppId());
+        return RestResponseBody.success(
+            SparkPipelineAssembler.toDetailResponse(pipeline.map(ApplicationBuildPipeline::toView).orElse(null)));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkSqlController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkSqlController.java
index cd93c1c..07126e3 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkSqlController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkSqlController.java
@@ -18,12 +18,21 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.exception.InternalException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
-import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.assembler.SparkSqlAssembler;
 import org.apache.streampark.console.core.entity.SparkSql;
+import org.apache.streampark.console.core.request.spark.SparkSqlCompleteRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlDeleteRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlGetRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlHistoryRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlListQueryRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlVerifyRequest;
+import org.apache.streampark.console.core.response.spark.SparkSqlResponse;
+import org.apache.streampark.console.core.response.sql.SqlCompleteResponse;
 import org.apache.streampark.console.core.service.SparkSqlService;
 import org.apache.streampark.console.core.service.SqlCompleteService;
 import org.apache.streampark.console.core.service.VariableService;
@@ -39,7 +48,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.Valid;
 
 import java.util.List;
 
@@ -63,69 +72,74 @@
     private SqlCompleteService sqlComplete;
 
     @PostMapping("verify")
-    public RestResponse verify(String sql, Long versionId, Long teamId) {
-        sql = variableService.replaceVariable(teamId, sql);
-        SparkSqlValidationResult sparkSqlValidationResult = sparkSqlService.verifySql(sql, versionId);
+    public RestResponseBody<Boolean> verify(@Valid SparkSqlVerifyRequest request) {
+        String sql = variableService.replaceVariable(request.getTeamId(), request.getSql());
+        SparkSqlValidationResult sparkSqlValidationResult = sparkSqlService.verifySql(sql, request.getVersionId());
         if (!sparkSqlValidationResult.success()) {
-            // record error type, such as error sql, reason and error start/end line
             String exception = sparkSqlValidationResult.exception();
-            RestResponse response = RestResponse.success()
-                .data(false)
-                .message(exception)
-                .put(TYPE, sparkSqlValidationResult.failedType().getFailedType())
-                .put(START, sparkSqlValidationResult.lineStart())
-                .put(END, sparkSqlValidationResult.lineEnd());
-
+            RestResponseBody<Boolean> response = RestResponseBody.success(false).message(exception);
+            response.extra(TYPE, sparkSqlValidationResult.failedType().getFailedType());
+            response.extra(START, sparkSqlValidationResult.lineStart());
+            response.extra(END, sparkSqlValidationResult.lineEnd());
             if (sparkSqlValidationResult.errorLine() > 0) {
-                response
-                    .put(START, sparkSqlValidationResult.errorLine())
-                    .put(END, sparkSqlValidationResult.errorLine() + 1);
+                response.extra(START, sparkSqlValidationResult.errorLine());
+                response.extra(END, sparkSqlValidationResult.errorLine() + 1);
             }
             return response;
         }
-        return RestResponse.success(true);
+        return RestResponseBody.success(true);
     }
 
     @PostMapping("list")
-    @Permission(app = "#sparkSql.appId", team = "#sparkSql.teamId")
-    public RestResponse list(SparkSql sparkSql, RestRequest request) {
-        IPage<SparkSql> page = sparkSqlService.getPage(sparkSql.getAppId(), request);
-        return RestResponse.success(page);
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<IPage<SparkSqlResponse>> list(@Valid SparkSqlListQueryRequest request,
+                                                          RestRequest restRequest) {
+        IPage<SparkSql> page = sparkSqlService.getPage(request.getAppId(), restRequest);
+        return RestResponseBody.success(SparkSqlAssembler.toPageResponse(page));
     }
 
     @PostMapping("delete")
     @RequiresPermissions("sql:delete")
-    @Permission(app = "#sparkSql.appId", team = "#sparkSql.teamId")
-    public RestResponse delete(SparkSql sparkSql) {
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<Boolean> delete(@Valid @FormOrJson SparkSqlDeleteRequest request) {
+        SparkSql sparkSql = SparkSqlAssembler.toDeleteEntity(request);
+        ApiAlertException.throwIfNull(sparkSql, "Spark SQL delete request cannot be null.");
         Boolean deleted = sparkSqlService.removeById(sparkSql.getSql());
-        return RestResponse.success(deleted);
+        return RestResponseBody.success(deleted);
     }
 
+    /** {@code data} is {@link SparkSqlResponse} for one id, or {@link SparkSqlResponse}{@code []} for two ids (legacy compare). */
+    @SuppressWarnings("java:S1452")
     @PostMapping("get")
-    @Permission(app = "#appId", team = "#teamId")
-    public RestResponse get(Long appId, Long teamId, String id) throws InternalException {
+    @Permission(app = "#request.appId", team = "#request.teamId")
+    public RestResponseBody<?> get(@Valid SparkSqlGetRequest request) throws InternalException {
         ApiAlertException.throwIfTrue(
-            appId == null || teamId == null, "Permission denied, appId and teamId cannot be null");
-        String[] array = id.split(",");
+            request.getAppId() == null || request.getTeamId() == null,
+            "Permission denied, appId and teamId cannot be null");
+        String[] array = request.getId().split(",");
         SparkSql sparkSql1 = sparkSqlService.getById(array[0]);
+        ApiAlertException.throwIfNull(sparkSql1, "Spark SQL not found.");
         sparkSql1.base64Encode();
         if (array.length == 1) {
-            return RestResponse.success(sparkSql1);
+            return RestResponseBody.success(SparkSqlAssembler.toResponse(sparkSql1));
         }
         SparkSql sparkSql2 = sparkSqlService.getById(array[1]);
+        ApiAlertException.throwIfNull(sparkSql2, "Spark SQL not found.");
         sparkSql2.base64Encode();
-        return RestResponse.success(new SparkSql[]{sparkSql1, sparkSql2});
+        return RestResponseBody.success(SparkSqlAssembler.toResponseArray(new SparkSql[]{sparkSql1, sparkSql2}));
     }
 
     @PostMapping("history")
-    @Permission(app = "#app.id", team = "#app.teamId")
-    public RestResponse history(FlinkApplication app) {
-        List<SparkSql> sqlList = sparkSqlService.listSparkSqlHistory(app.getId());
-        return RestResponse.success(sqlList);
+    @Permission(app = "#request.id", team = "#request.teamId")
+    public RestResponseBody<List<SparkSqlResponse>> history(@Valid SparkSqlHistoryRequest request) {
+        List<SparkSql> sqlList = sparkSqlService.listSparkSqlHistory(request.getId());
+        return RestResponseBody.success(SparkSqlAssembler.toListResponse(sqlList));
     }
 
     @PostMapping("sqlComplete")
-    public RestResponse getSqlComplete(@NotNull(message = "{required}") String sql) {
-        return RestResponse.success().put("word", sqlComplete.getComplete(sql));
+    public RestResponseBody<SqlCompleteResponse> getSqlComplete(@Valid SparkSqlCompleteRequest request) {
+        SqlCompleteResponse response = new SqlCompleteResponse();
+        response.setWord(sqlComplete.getComplete(request.getSql()));
+        return RestResponseBody.success(response);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/VariableController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/VariableController.java
index 1abb889..716e071 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/VariableController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/VariableController.java
@@ -18,9 +18,20 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.FlinkApplicationAssembler;
+import org.apache.streampark.console.core.assembler.VariableAssembler;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.entity.Variable;
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+import org.apache.streampark.console.core.request.variable.VariableCheckCodeRequest;
+import org.apache.streampark.console.core.request.variable.VariableCreateRequest;
+import org.apache.streampark.console.core.request.variable.VariableListRequest;
+import org.apache.streampark.console.core.request.variable.VariablePageQueryRequest;
+import org.apache.streampark.console.core.request.variable.VariableUpdateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkAppResponse;
+import org.apache.streampark.console.core.response.variable.VariableResponse;
 import org.apache.streampark.console.core.service.VariableService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -33,11 +44,9 @@
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
 
 import java.util.List;
 
@@ -50,79 +59,67 @@
     @Autowired
     private VariableService variableService;
 
-    /**
-     * Get variable list by page.
-     *
-     * @param restRequest
-     * @param variable
-     * @return
-     */
     @PostMapping("page")
     @RequiresPermissions("variable:view")
-    public RestResponse page(RestRequest restRequest, Variable variable) {
-        IPage<Variable> page = variableService.getPage(variable, restRequest);
+    public RestResponseBody<IPage<VariableResponse>> page(RestRequest restRequest, VariablePageQueryRequest query) {
+        IPage<Variable> page =
+            variableService.getPage(VariableAssembler.toEntity(query), restRequest);
         for (Variable v : page.getRecords()) {
             v.dataMasking();
         }
-        return RestResponse.success(page);
+        return RestResponseBody.success(VariableAssembler.toPageResponse(page));
     }
 
-    /**
-     * Get variables through team and search keywords.
-     *
-     * @param teamId
-     * @param keyword Fuzzy search keywords through variable code or description, Nullable.
-     * @return
-     */
     @PostMapping("list")
-    public RestResponse variableList(@RequestParam Long teamId, String keyword) {
-        List<Variable> variableList = variableService.listByTeamId(teamId, keyword);
+    public RestResponseBody<List<VariableResponse>> variableList(VariableListRequest request) {
+        List<Variable> variableList =
+            variableService.listByTeamId(request.getTeamId(), request.getKeyword());
         for (Variable v : variableList) {
             v.dataMasking();
         }
-        return RestResponse.success(variableList);
+        return RestResponseBody.success(VariableAssembler.toListResponse(variableList));
     }
 
     @PostMapping("depend_apps")
     @RequiresPermissions("variable:depend_apps")
-    public RestResponse dependApps(RestRequest restRequest, Variable variable) {
-        IPage<FlinkApplication> dependApps = variableService.getDependAppsPage(variable, restRequest);
-        return RestResponse.success(dependApps);
+    public RestResponseBody<IPage<FlinkAppResponse>> dependApps(RestRequest restRequest, TeamScopedIdRequest request) {
+        IPage<FlinkApplication> dependApps =
+            variableService.getDependAppsPage(VariableAssembler.toEntity(request), restRequest);
+        return RestResponseBody.success(FlinkApplicationAssembler.toPageResponse(dependApps));
     }
 
     @PostMapping("post")
     @RequiresPermissions("variable:add")
-    public RestResponse addVariable(@Valid Variable variable) {
-        this.variableService.createVariable(variable);
-        return RestResponse.success();
+    public RestResponseBody<Void> addVariable(@Valid @FormOrJson VariableCreateRequest request) {
+        this.variableService.createVariable(VariableAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PutMapping("update")
     @RequiresPermissions("variable:update")
-    public RestResponse updateVariable(@Valid Variable variable) {
-        variableService.updateVariable(variable);
-        return RestResponse.success();
+    public RestResponseBody<Void> updateVariable(@Valid @FormOrJson VariableUpdateRequest request) {
+        variableService.updateVariable(VariableAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("show_original")
     @RequiresPermissions("variable:show_original")
-    public RestResponse showOriginal(@RequestParam Long id) {
-        Variable v = this.variableService.getById(id);
-        return RestResponse.success(v);
+    public RestResponseBody<VariableResponse> showOriginal(TeamScopedIdRequest request) {
+        Variable v = this.variableService.getById(request.getId());
+        return RestResponseBody.success(VariableAssembler.toResponse(v));
     }
 
     @DeleteMapping("delete")
     @RequiresPermissions("variable:delete")
-    public RestResponse deleteVariable(@Valid Variable variable) {
-        this.variableService.remove(variable);
-        return RestResponse.success();
+    public RestResponseBody<Void> deleteVariable(@Valid @FormOrJson TeamScopedIdRequest request) {
+        this.variableService.remove(VariableAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("check/code")
-    public RestResponse checkVariableCode(
-                                          @RequestParam Long teamId,
-                                          @NotBlank(message = "{required}") String variableCode) {
-        boolean result = this.variableService.findByVariableCode(teamId, variableCode) == null;
-        return RestResponse.success(result);
+    public RestResponseBody<Boolean> checkVariableCode(@Valid VariableCheckCodeRequest request) {
+        boolean result =
+            this.variableService.findByVariableCode(request.getTeamId(), request.getVariableCode()) == null;
+        return RestResponseBody.success(result);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/YarnQueueController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/YarnQueueController.java
index 8f297fa..0d9f844 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/YarnQueueController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/YarnQueueController.java
@@ -18,8 +18,16 @@
 package org.apache.streampark.console.core.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.core.assembler.YarnQueueAssembler;
 import org.apache.streampark.console.core.entity.YarnQueue;
+import org.apache.streampark.console.core.request.yarn.YarnQueueCreateRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueDeleteRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueListQueryRequest;
+import org.apache.streampark.console.core.request.yarn.YarnQueueUpdateRequest;
+import org.apache.streampark.console.core.response.yarn.YarnQueueCheckResponse;
+import org.apache.streampark.console.core.response.yarn.YarnQueueResponse;
 import org.apache.streampark.console.core.service.YarnQueueService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -32,6 +40,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.validation.Valid;
+
 @Slf4j
 @Validated
 @RestController
@@ -41,41 +51,36 @@
     @Autowired
     private YarnQueueService yarnQueueService;
 
-    /**
-     * * List the queues in the specified team by the paging & optional search hint message.
-     *
-     * @param restRequest page request information.
-     * @param yarnQueue optional fields used to search.
-     * @return RestResponse with IPage<{@link YarnQueue}> object.
-     */
     @PostMapping("list")
-    public RestResponse list(RestRequest restRequest, YarnQueue yarnQueue) {
-        IPage<YarnQueue> queuePage = yarnQueueService.getPage(yarnQueue, restRequest);
-        return RestResponse.success(queuePage);
+    public RestResponseBody<IPage<YarnQueueResponse>> list(RestRequest restRequest, YarnQueueListQueryRequest query) {
+        IPage<YarnQueue> queuePage =
+            yarnQueueService.getPage(YarnQueueAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(YarnQueueAssembler.toPageResponse(queuePage));
     }
 
     @PostMapping("check")
-    public RestResponse check(YarnQueue yarnQueue) {
-        return RestResponse.success(yarnQueueService.checkYarnQueue(yarnQueue));
+    public RestResponseBody<YarnQueueCheckResponse> check(YarnQueueCreateRequest request) {
+        return RestResponseBody.success(
+            YarnQueueAssembler.toCheckResponse(yarnQueueService.checkYarnQueue(YarnQueueAssembler.toEntity(request))));
     }
 
     @PostMapping("create")
     @RequiresPermissions("yarnQueue:create")
-    public RestResponse create(YarnQueue yarnQueue) {
-        return RestResponse.success(yarnQueueService.createYarnQueue(yarnQueue));
+    public RestResponseBody<Boolean> create(@Valid @FormOrJson YarnQueueCreateRequest request) {
+        return RestResponseBody.success(yarnQueueService.createYarnQueue(YarnQueueAssembler.toEntity(request)));
     }
 
     @PostMapping("update")
     @RequiresPermissions("yarnQueue:update")
-    public RestResponse update(YarnQueue yarnQueue) {
-        yarnQueueService.updateYarnQueue(yarnQueue);
-        return RestResponse.success();
+    public RestResponseBody<Void> update(@Valid @FormOrJson YarnQueueUpdateRequest request) {
+        yarnQueueService.updateYarnQueue(YarnQueueAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PostMapping("delete")
     @RequiresPermissions("yarnQueue:delete")
-    public RestResponse delete(YarnQueue yarnQueue) {
-        yarnQueueService.remove(yarnQueue);
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson YarnQueueDeleteRequest request) {
+        yarnQueueService.remove(YarnQueueAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/entity/AlertConfig.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/entity/AlertConfig.java
index 00c857b..c6c084e 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/entity/AlertConfig.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/entity/AlertConfig.java
@@ -18,18 +18,14 @@
 package org.apache.streampark.console.core.entity;
 
 import org.apache.streampark.console.base.mybatis.entity.BaseEntity;
-import org.apache.streampark.console.base.util.JacksonUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
 
 @Getter
 @Setter
@@ -63,39 +59,4 @@
 
     /** lark alert parameters */
     private String larkParams;
-
-    public static AlertConfig of(AlertConfigParams params) {
-        if (params == null) {
-            return null;
-        }
-        AlertConfig alertConfig = new AlertConfig();
-        BeanUtils.copyProperties(
-            params,
-            alertConfig,
-            "emailParams",
-            "dingTalkParams",
-            "weComParams",
-            "httpCallbackParams",
-            "larkParams");
-        try {
-            if (params.getEmailParams() != null) {
-                alertConfig.setEmailParams(JacksonUtils.write(params.getEmailParams()));
-            }
-            if (params.getDingTalkParams() != null) {
-                alertConfig.setDingTalkParams(JacksonUtils.write(params.getDingTalkParams()));
-            }
-            if (params.getWeComParams() != null) {
-                alertConfig.setWeComParams(JacksonUtils.write(params.getWeComParams()));
-            }
-            if (params.getHttpCallbackParams() != null) {
-                alertConfig.setHttpCallbackParams(JacksonUtils.write(params.getHttpCallbackParams()));
-            }
-            if (params.getLarkParams() != null) {
-                alertConfig.setLarkParams(JacksonUtils.write(params.getLarkParams()));
-            }
-        } catch (JsonProcessingException e) {
-            log.error("Json write failed", e);
-        }
-        return alertConfig;
-    }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigExistsRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigExistsRequest.java
new file mode 100644
index 0000000..4ba61cc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigExistsRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.alert;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /flink/alert/exists}. */
+@Getter
+@Setter
+public class AlertConfigExistsRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String alertName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigIdRequest.java
new file mode 100644
index 0000000..79bd627
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigIdRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.core.request.alert;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /flink/alert/get}. */
+@Getter
+@Setter
+public class AlertConfigIdRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigPageRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigPageRequest.java
new file mode 100644
index 0000000..249ca61
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigPageRequest.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 org.apache.streampark.console.core.request.alert;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /flink/alert/page}. */
+@Getter
+@Setter
+public class AlertConfigPageRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigRequest.java
new file mode 100644
index 0000000..7990bdb
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertConfigRequest.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 org.apache.streampark.console.core.request.alert;
+
+import org.apache.streampark.console.core.bean.AlertDingTalkParams;
+import org.apache.streampark.console.core.bean.AlertEmailParams;
+import org.apache.streampark.console.core.bean.AlertHttpCallbackParams;
+import org.apache.streampark.console.core.bean.AlertLarkParams;
+import org.apache.streampark.console.core.bean.AlertWeComParams;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for alert config create/update/exists, aligned with webapp {@code AlertCreate}. */
+@Getter
+@Setter
+public class AlertConfigRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long userId;
+
+    @NotBlank
+    private String alertName;
+
+    @NotNull
+    private Integer alertType;
+
+    private AlertEmailParams emailParams;
+
+    private AlertDingTalkParams dingTalkParams;
+
+    private AlertWeComParams weComParams;
+
+    private AlertHttpCallbackParams httpCallbackParams;
+
+    private AlertLarkParams larkParams;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertSendRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertSendRequest.java
new file mode 100644
index 0000000..0ee508c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/alert/AlertSendRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.core.request.alert;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /flink/alert/send}. */
+@Getter
+@Setter
+public class AlertSendRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupDeleteRequest.java
new file mode 100644
index 0000000..ba3e19f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupDeleteRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class AppBackupDeleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupQueryRequest.java
new file mode 100644
index 0000000..e97ee62
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppBackupQueryRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class AppBackupQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long appId;
+
+    private String teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogDeleteRequest.java
new file mode 100644
index 0000000..d5b8753
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogDeleteRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class AppOptLogDeleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private String teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogQueryRequest.java
new file mode 100644
index 0000000..2514f75
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/app/AppOptLogQueryRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class AppOptLogQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long appId;
+
+    private String teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppScopedIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppScopedIdRequest.java
new file mode 100644
index 0000000..e7ea579
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppScopedIdRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Application id ({@code id}) scoped to a team ({@code teamId}) for {@code @Permission} checks.
+ */
+@Getter
+@Setter
+public class AppScopedIdRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppTeamQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppTeamQueryRequest.java
new file mode 100644
index 0000000..eb2b04f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/AppTeamQueryRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Team-scoped query carrying an explicit {@code appId} (distinct from {@link IdRequest#id}).
+ */
+@Getter
+@Setter
+public class AppTeamQueryRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/IdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/IdRequest.java
new file mode 100644
index 0000000..9627f2d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/IdRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class IdRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/SqlVerifyRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/SqlVerifyRequest.java
new file mode 100644
index 0000000..bd82d17
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/SqlVerifyRequest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Shared SQL verify request for Flink and Spark SQL controllers. */
+@Getter
+@Setter
+public class SqlVerifyRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    @ApiParam(description = "SQL statement to validate", required = true)
+    private String sql;
+
+    @NotNull
+    @ApiParam(description = "Engine version id", required = true)
+    private Long versionId;
+
+    @NotNull
+    @ApiParam(description = "Team id", required = true)
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamIdRequest.java
new file mode 100644
index 0000000..75050a7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamIdRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class TeamIdRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamScopedIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamScopedIdRequest.java
new file mode 100644
index 0000000..ba88ed7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/common/TeamScopedIdRequest.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 org.apache.streampark.console.core.request.common;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+@Getter
+@Setter
+public class TeamScopedIdRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkCreateRequest.java
new file mode 100644
index 0000000..1c0a4d4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkCreateRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.externallink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /flink/externalLink/create}. */
+@Getter
+@Setter
+public class ExternalLinkCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String badgeLabel;
+
+    @NotBlank
+    private String badgeName;
+
+    private String badgeColor;
+
+    @NotBlank
+    private String linkUrl;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkRenderRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkRenderRequest.java
new file mode 100644
index 0000000..8cf9799
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkRenderRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.externallink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /flink/externalLink/render}. */
+@Getter
+@Setter
+public class ExternalLinkRenderRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "The flink app id cannot be null")
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkUpdateRequest.java
new file mode 100644
index 0000000..71fce29
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/externallink/ExternalLinkUpdateRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.externallink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code POST /flink/externalLink/update}. */
+@Getter
+@Setter
+public class ExternalLinkUpdateRequest extends ExternalLinkCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCancelRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCancelRequest.java
new file mode 100644
index 0000000..e6e43b2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCancelRequest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/cancel}, aligned with webapp {@code CancelParam}.
+ */
+@Getter
+@Setter
+public class FlinkAppCancelRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    @ApiParam(description = "Application id", required = true)
+    private Long id;
+
+    @NotNull
+    @ApiParam(description = "Team id", required = true)
+    private Long teamId;
+
+    @ApiParam(name = "triggerSavepoint", description = "Trigger savepoint before stopping", defaultValue = "false")
+    private Boolean restoreOrTriggerSavepoint;
+
+    @ApiParam(description = "Drain pipeline before canceling", defaultValue = "false")
+    private Boolean drain;
+
+    private Boolean nativeFormat;
+
+    @ApiParam(description = "Savepoint path")
+    private String savepointPath;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckNameRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckNameRequest.java
new file mode 100644
index 0000000..3120e08
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckNameRequest.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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/check/name}.
+ */
+@Getter
+@Setter
+public class FlinkAppCheckNameRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    @NotBlank
+    private String jobName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckSavepointPathRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckSavepointPathRequest.java
new file mode 100644
index 0000000..7ed9303
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCheckSavepointPathRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/check/savepoint_path}.
+ */
+@Getter
+@Setter
+public class FlinkAppCheckSavepointPathRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private String savepointPath;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppConfigRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppConfigRequest.java
new file mode 100644
index 0000000..fc315d2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppConfigRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/read_conf} and {@code POST /flink/app/name}.
+ */
+@Getter
+@Setter
+public class FlinkAppConfigRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private String config;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCopyRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCopyRequest.java
new file mode 100644
index 0000000..550533d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCopyRequest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/copy}.
+ */
+@Getter
+@Setter
+public class FlinkAppCopyRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+
+    private Long teamId;
+
+    @NotBlank
+    private String jobName;
+
+    private String args;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCreateRequest.java
new file mode 100644
index 0000000..ce58390
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppCreateRequest.java
@@ -0,0 +1,128 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/create}, aligned with webapp {@code CreateParams}.
+ */
+@Getter
+@Setter
+public class FlinkAppCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    @ApiParam(description = "Team id", required = true)
+    private Long teamId;
+
+    @NotNull
+    @ApiParam(description = "Job type", required = true)
+    private Integer jobType;
+
+    @NotNull
+    @ApiParam(description = "Deploy mode", required = true)
+    private Integer deployMode;
+
+    @NotNull
+    @ApiParam(description = "Flink version id", required = true)
+    private Long versionId;
+
+    private String flinkSql;
+
+    @NotNull
+    @ApiParam(description = "Application type", required = true)
+    private Integer appType;
+
+    private String config;
+
+    private Integer format;
+
+    @NotBlank
+    @ApiParam(description = "Job name", required = true)
+    private String jobName;
+
+    private String tags;
+
+    private String args;
+
+    private String dependency;
+
+    private String options;
+
+    private Integer cpMaxFailureInterval;
+
+    private Integer cpFailureRateInterval;
+
+    private Integer cpFailureAction;
+
+    private String dynamicProperties;
+
+    private Integer resolveOrder;
+
+    private Integer restartSize;
+
+    private Long alertId;
+
+    private String description;
+
+    private String k8sNamespace;
+
+    private String clusterId;
+
+    private Long flinkClusterId;
+
+    private String flinkImage;
+
+    private String jar;
+
+    private String mainClass;
+
+    private Long projectId;
+
+    private String module;
+
+    private Integer resourceFrom;
+
+    private Boolean build;
+
+    private String hotParams;
+
+    private Integer k8sRestExposedType;
+
+    private String k8sPodTemplate;
+
+    private String k8sJmPodTemplate;
+
+    private String k8sTmPodTemplate;
+
+    private String ingressTemplate;
+
+    private Boolean k8sHadoopIntegration;
+
+    private String serviceAccount;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppGetMainRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppGetMainRequest.java
new file mode 100644
index 0000000..44e79de
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppGetMainRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/main}.
+ */
+@Getter
+@Setter
+public class FlinkAppGetMainRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private Long projectId;
+
+    private String jar;
+
+    private String module;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppIdRequest.java
new file mode 100644
index 0000000..811fde3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppIdRequest.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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.AppScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Minimal request carrying a Flink application id (and optional team id for permission checks).
+ */
+@Getter
+@Setter
+public class FlinkAppIdRequest extends AppScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppK8sLogRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppK8sLogRequest.java
new file mode 100644
index 0000000..ff7b51c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppK8sLogRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/k8s_log}.
+ */
+@Getter
+@Setter
+public class FlinkAppK8sLogRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Integer offset;
+
+    private Integer limit;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppListQueryRequest.java
new file mode 100644
index 0000000..680de9a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppListQueryRequest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /flink/app/list}.
+ */
+@Getter
+@Setter
+public class FlinkAppListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    private Integer jobType;
+
+    private Integer[] jobTypeArray;
+
+    private Integer deployMode;
+
+    private String jobName;
+
+    private String projectName;
+
+    private Integer[] stateArray;
+
+    private String tags;
+
+    private Long userId;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppMappingRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppMappingRequest.java
new file mode 100644
index 0000000..c811b0a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppMappingRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /flink/app/mapping}.
+ */
+@Getter
+@Setter
+public class FlinkAppMappingRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String clusterId;
+
+    private String jobId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppStartRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppStartRequest.java
new file mode 100644
index 0000000..2d074b1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppStartRequest.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/app/start}.
+ */
+@Getter
+@Setter
+public class FlinkAppStartRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    @ApiParam(description = "Application id", required = true)
+    private Long id;
+
+    @NotNull
+    @ApiParam(description = "Team id", required = true)
+    private Long teamId;
+
+    @ApiParam(name = "restoreFromSavepoint", description = "Restore from savepoint or checkpoint", defaultValue = "false")
+    private Boolean restoreOrTriggerSavepoint;
+
+    @ApiParam(description = "Savepoint or checkpoint path")
+    private String savepointPath;
+
+    @ApiParam(description = "Allow non restored state", defaultValue = "false")
+    private Boolean allowNonRestored;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppUpdateRequest.java
new file mode 100644
index 0000000..d0a5cad
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkAppUpdateRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.annotation.ApiParam;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /flink/app/update}.
+ */
+@Getter
+@Setter
+public class FlinkAppUpdateRequest extends FlinkAppCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    @ApiParam(description = "Application id", required = true)
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCheckRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCheckRequest.java
new file mode 100644
index 0000000..8690bdc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCheckRequest.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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /flink/cluster/check}.
+ */
+@Getter
+@Setter
+public class FlinkClusterCheckRequest extends FlinkClusterCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCreateRequest.java
new file mode 100644
index 0000000..a1b02b4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterCreateRequest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/cluster/create}, aligned with webapp {@code FlinkCluster}.
+ */
+@Getter
+@Setter
+public class FlinkClusterCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String address;
+
+    private String jobManagerUrl;
+
+    private String clusterId;
+
+    @NotBlank
+    private String clusterName;
+
+    @NotNull
+    private Integer deployMode;
+
+    private Long versionId;
+
+    private String k8sNamespace;
+
+    private String serviceAccount;
+
+    private String description;
+
+    private String flinkImage;
+
+    private String options;
+
+    private String yarnQueue;
+
+    private Boolean k8sHadoopIntegration;
+
+    private String dynamicProperties;
+
+    private Integer k8sRestExposedType;
+
+    private String k8sConf;
+
+    private Integer resolveOrder;
+
+    private Long alertId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterPageQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterPageQueryRequest.java
new file mode 100644
index 0000000..8ad950c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterPageQueryRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /flink/cluster/page}.
+ */
+@Getter
+@Setter
+public class FlinkClusterPageQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String clusterName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterUpdateRequest.java
new file mode 100644
index 0000000..efe86d8
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkClusterUpdateRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /flink/cluster/update}.
+ */
+@Getter
+@Setter
+public class FlinkClusterUpdateRequest extends FlinkClusterCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkConfListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkConfListQueryRequest.java
new file mode 100644
index 0000000..991585f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkConfListQueryRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /flink/conf/list}.
+ */
+@Getter
+@Setter
+public class FlinkConfListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCheckRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCheckRequest.java
new file mode 100644
index 0000000..1ffc5b9
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCheckRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/env/check} and {@code POST /flink/env/validity}.
+ */
+@Getter
+@Setter
+public class FlinkEnvCheckRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String flinkName;
+
+    private String flinkHome;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCreateRequest.java
new file mode 100644
index 0000000..c20d47e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvCreateRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/env/create}, aligned with webapp {@code FlinkCreate}.
+ */
+@Getter
+@Setter
+public class FlinkEnvCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String flinkName;
+
+    @NotBlank
+    private String flinkHome;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvPageQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvPageQueryRequest.java
new file mode 100644
index 0000000..3b86d45
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvPageQueryRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /flink/env/page}.
+ */
+@Getter
+@Setter
+public class FlinkEnvPageQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String flinkName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvUpdateRequest.java
new file mode 100644
index 0000000..2121eef
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkEnvUpdateRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /flink/env/update}.
+ */
+@Getter
+@Setter
+public class FlinkEnvUpdateRequest extends FlinkEnvCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkHistoryDeployModeRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkHistoryDeployModeRequest.java
new file mode 100644
index 0000000..a6cef39
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkHistoryDeployModeRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/history/session_cluster_ids}.
+ */
+@Getter
+@Setter
+public class FlinkHistoryDeployModeRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private int deployMode;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineBuildRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineBuildRequest.java
new file mode 100644
index 0000000..0bbad14
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineBuildRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/pipe/build}.
+ */
+@Getter
+@Setter
+public class FlinkPipelineBuildRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+
+    private boolean forceBuild;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineDetailRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineDetailRequest.java
new file mode 100644
index 0000000..26cbfbb
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPipelineDetailRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/pipe/detail}.
+ */
+@Getter
+@Setter
+public class FlinkPipelineDetailRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateExtractRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateExtractRequest.java
new file mode 100644
index 0000000..09193d5
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateExtractRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/podtmpl/extract_host_alias}.
+ */
+@Getter
+@Setter
+public class FlinkPodTemplateExtractRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String podTemplate;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateHostAliasRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateHostAliasRequest.java
new file mode 100644
index 0000000..e3dcaea
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplateHostAliasRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/podtmpl/comp_host_alias}.
+ */
+@Getter
+@Setter
+public class FlinkPodTemplateHostAliasRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String hosts;
+
+    @NotBlank
+    private String podTemplate;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplatePreviewRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplatePreviewRequest.java
new file mode 100644
index 0000000..8e48f4b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkPodTemplatePreviewRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/podtmpl/preview_host_alias}.
+ */
+@Getter
+@Setter
+public class FlinkPodTemplatePreviewRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String hosts;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlCompleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlCompleteRequest.java
new file mode 100644
index 0000000..30ff303
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlCompleteRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/sql/sql_complete}.
+ */
+@Getter
+@Setter
+public class FlinkSqlCompleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private String sql;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlDeleteRequest.java
new file mode 100644
index 0000000..ecc94ec
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlDeleteRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /flink/sql/delete}.
+ */
+@Getter
+@Setter
+public class FlinkSqlDeleteRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlGetRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlGetRequest.java
new file mode 100644
index 0000000..fd04a7a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlGetRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Request body for {@code POST /flink/sql/get}.
+ */
+@Getter
+@Setter
+public class FlinkSqlGetRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlListQueryRequest.java
new file mode 100644
index 0000000..f559877
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlListQueryRequest.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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Query filters for {@code POST /flink/sql/list}.
+ */
+@Getter
+@Setter
+public class FlinkSqlListQueryRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlVerifyRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlVerifyRequest.java
new file mode 100644
index 0000000..e87679e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/FlinkSqlVerifyRequest.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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.SqlVerifyRequest;
+
+/** Request body for {@code POST /flink/sql/verify}. */
+public class FlinkSqlVerifyRequest extends SqlVerifyRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPICurlRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPICurlRequest.java
new file mode 100644
index 0000000..e329b3d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPICurlRequest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /openapi/curl}.
+ */
+@Getter
+@Setter
+public class OpenAPICurlRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String name;
+
+    private String baseUrl;
+
+    private Long appId;
+
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPISchemaRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPISchemaRequest.java
new file mode 100644
index 0000000..0585032
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/OpenAPISchemaRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /openapi/schema}.
+ */
+@Getter
+@Setter
+public class OpenAPISchemaRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String name;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointDeleteRequest.java
new file mode 100644
index 0000000..48fdb50
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointDeleteRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /flink/savepoint/delete}.
+ */
+@Getter
+@Setter
+public class SavepointDeleteRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointHistoryQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointHistoryQueryRequest.java
new file mode 100644
index 0000000..bfe2781
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointHistoryQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /flink/savepoint/history}.
+ */
+@Getter
+@Setter
+public class SavepointHistoryQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long appId;
+
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointTriggerRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointTriggerRequest.java
new file mode 100644
index 0000000..e146107
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/flink/SavepointTriggerRequest.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 org.apache.streampark.console.core.request.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /flink/savepoint/trigger}.
+ */
+@Getter
+@Setter
+public class SavepointTriggerRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+
+    @NotNull
+    private Long teamId;
+
+    private String savepointPath;
+
+    private Boolean nativeFormat;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageDeleteRequest.java
new file mode 100644
index 0000000..a9c6ad3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageDeleteRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.core.request.message;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /message/delete}. */
+@Getter
+@Setter
+public class MessageDeleteRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageNoticeRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageNoticeRequest.java
new file mode 100644
index 0000000..70dd5c6
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/message/MessageNoticeRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.message;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /message/notice}. */
+@Getter
+@Setter
+public class MessageNoticeRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Integer type;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectBuildLogRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectBuildLogRequest.java
new file mode 100644
index 0000000..f993ede
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectBuildLogRequest.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 org.apache.streampark.console.core.request.project;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /project/build_log}. */
+@Getter
+@Setter
+public class ProjectBuildLogRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long startOffset;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectCreateRequest.java
new file mode 100644
index 0000000..146000f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectCreateRequest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.apache.streampark.console.core.request.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /project/create}. */
+@Getter
+@Setter
+public class ProjectCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    @NotBlank
+    private String name;
+
+    @NotBlank
+    private String url;
+
+    private String refs;
+
+    private String userName;
+
+    private String password;
+
+    private String prvkeyPath;
+
+    private Integer repository;
+
+    private String pom;
+
+    private String buildArgs;
+
+    private String description;
+
+    private Integer type;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectExistsRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectExistsRequest.java
new file mode 100644
index 0000000..f1b962f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectExistsRequest.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 org.apache.streampark.console.core.request.project;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /project/exists}. */
+@Getter
+@Setter
+public class ProjectExistsRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String name;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectGitRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectGitRequest.java
new file mode 100644
index 0000000..c113aa4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectGitRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.project;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request for git-related project operations (branches, git_check). */
+@Getter
+@Setter
+public class ProjectGitRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String url;
+
+    private String refs;
+
+    private String userName;
+
+    private String password;
+
+    private String prvkeyPath;
+
+    private Integer repository;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectListQueryRequest.java
new file mode 100644
index 0000000..f7087eb
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectListQueryRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /project/list}. */
+@Getter
+@Setter
+public class ProjectListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long teamId;
+
+    private String name;
+
+    private Integer buildState;
+
+    private Integer type;
+
+    private String dateFrom;
+
+    private String dateTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectModuleRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectModuleRequest.java
new file mode 100644
index 0000000..2fc735b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectModuleRequest.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 org.apache.streampark.console.core.request.project;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request for project module/jar/conf operations. */
+@Getter
+@Setter
+public class ProjectModuleRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String module;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectUpdateRequest.java
new file mode 100644
index 0000000..a5d2d63
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/project/ProjectUpdateRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code POST /project/update}. */
+@Getter
+@Setter
+public class ProjectUpdateRequest extends ProjectCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceCreateRequest.java
new file mode 100644
index 0000000..1f2dbbd
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceCreateRequest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.streampark.console.core.request.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /resource/add}. */
+@Getter
+@Setter
+public class ResourceCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    private String resourceName;
+
+    private String resourcePath;
+
+    @NotBlank
+    private String resource;
+
+    private String description;
+
+    private String mainClass;
+
+    private String connectorRequiredOptions;
+
+    private String connectorOptionalOptions;
+
+    private String resourceType;
+
+    private String engineType;
+
+    private String connector;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourcePageQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourcePageQueryRequest.java
new file mode 100644
index 0000000..6ab8bb6
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourcePageQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.request.resource;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Query filters for {@code POST /resource/page}. */
+@Getter
+@Setter
+public class ResourcePageQueryRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String resourceName;
+
+    private String resourceType;
+
+    private String engineType;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceUpdateRequest.java
new file mode 100644
index 0000000..e6e7b22
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/resource/ResourceUpdateRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code PUT /resource/update}. */
+@Getter
+@Setter
+public class ResourceUpdateRequest extends ResourceCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingDockerRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingDockerRequest.java
new file mode 100644
index 0000000..b4ea290
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingDockerRequest.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 org.apache.streampark.console.core.request.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for docker setting endpoints. */
+@Getter
+@Setter
+public class SettingDockerRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String address;
+
+    private String username;
+
+    private String password;
+
+    private String namespace;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingEmailRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingEmailRequest.java
new file mode 100644
index 0000000..7ad2054
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingEmailRequest.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 org.apache.streampark.console.core.request.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for email setting endpoints. */
+@Getter
+@Setter
+public class SettingEmailRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String host;
+
+    private Integer port;
+
+    @NotBlank
+    private String from;
+
+    private String userName;
+
+    private String password;
+
+    private boolean ssl;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingGetRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingGetRequest.java
new file mode 100644
index 0000000..614a010
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingGetRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /setting/get}. */
+@Getter
+@Setter
+public class SettingGetRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String key;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingUpdateRequest.java
new file mode 100644
index 0000000..7b0f36c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/setting/SettingUpdateRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /setting/update}. */
+@Getter
+@Setter
+public class SettingUpdateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String settingKey;
+
+    private String settingValue;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCancelRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCancelRequest.java
new file mode 100644
index 0000000..a33ff27
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCancelRequest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/cancel}.
+ */
+@Getter
+@Setter
+public class SparkAppCancelRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+
+    @NotNull
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCheckNameRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCheckNameRequest.java
new file mode 100644
index 0000000..4851b9a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCheckNameRequest.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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/check/name}.
+ */
+@Getter
+@Setter
+public class SparkAppCheckNameRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    @NotBlank
+    private String appName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppConfigRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppConfigRequest.java
new file mode 100644
index 0000000..5a3f2cc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppConfigRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/read_conf} and {@code POST /spark/app/name}.
+ */
+@Getter
+@Setter
+public class SparkAppConfigRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private String config;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCopyRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCopyRequest.java
new file mode 100644
index 0000000..b8ff557
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCopyRequest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/copy}.
+ */
+@Getter
+@Setter
+public class SparkAppCopyRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+
+    private Long teamId;
+
+    @NotBlank
+    private String appName;
+
+    private String appArgs;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCreateRequest.java
new file mode 100644
index 0000000..ee73011
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppCreateRequest.java
@@ -0,0 +1,112 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/create}, aligned with webapp {@code SparkApplication}.
+ */
+@Getter
+@Setter
+public class SparkAppCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    @NotNull
+    private Integer jobType;
+
+    @NotNull
+    private Integer appType;
+
+    @NotNull
+    private Long versionId;
+
+    @NotBlank
+    private String appName;
+
+    @NotNull
+    private Integer deployMode;
+
+    private Integer resourceFrom;
+
+    private Long projectId;
+
+    private String module;
+
+    private String mainClass;
+
+    private String jar;
+
+    private String appProperties;
+
+    private String appArgs;
+
+    private String yarnQueue;
+
+    private String k8sMasterUrl;
+
+    private String k8sContainerImage;
+
+    private Integer k8sImagePullPolicy;
+
+    private String k8sServiceAccount;
+
+    private String k8sNamespace;
+
+    private String k8sDriverPodTemplate;
+
+    private String k8sExecutorPodTemplate;
+
+    private Boolean k8sHadoopIntegration;
+
+    private String hadoopUser;
+
+    private Integer restartSize;
+
+    private Long alertId;
+
+    private String description;
+
+    private String tags;
+
+    private String options;
+
+    private Boolean build;
+
+    private String dependency;
+
+    private String teamResource;
+
+    private String sparkSql;
+
+    private String config;
+
+    private Integer format;
+
+    private Long sqlId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppIdRequest.java
new file mode 100644
index 0000000..e354439
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppIdRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.AppScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Minimal request carrying a Spark application id (and optional team id for permission checks).
+ */
+@Getter
+@Setter
+public class SparkAppIdRequest extends AppScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppListQueryRequest.java
new file mode 100644
index 0000000..a1b89dd
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppListQueryRequest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /spark/app/list}.
+ */
+@Getter
+@Setter
+public class SparkAppListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    private Integer jobType;
+
+    private Integer deployMode;
+
+    private String appName;
+
+    private String clusterId;
+
+    private Integer state;
+
+    private Long userId;
+
+    private String tags;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppMappingRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppMappingRequest.java
new file mode 100644
index 0000000..78b64c0
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppMappingRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /spark/app/mapping}.
+ */
+@Getter
+@Setter
+public class SparkAppMappingRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String clusterId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppStartRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppStartRequest.java
new file mode 100644
index 0000000..8713c0b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppStartRequest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/app/start}.
+ */
+@Getter
+@Setter
+public class SparkAppStartRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+
+    @NotNull
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppUpdateRequest.java
new file mode 100644
index 0000000..68bca3b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkAppUpdateRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /spark/app/update}.
+ */
+@Getter
+@Setter
+public class SparkAppUpdateRequest extends SparkAppCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfHistoryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfHistoryRequest.java
new file mode 100644
index 0000000..c4e8f30
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfHistoryRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /spark/conf/history}.
+ */
+@Getter
+@Setter
+public class SparkConfHistoryRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfListQueryRequest.java
new file mode 100644
index 0000000..d1148b2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkConfListQueryRequest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Query filters for {@code POST /spark/conf/list}.
+ */
+@Getter
+@Setter
+public class SparkConfListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long appId;
+
+    private Integer format;
+
+    private Integer version;
+
+    private Boolean latest;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCheckRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCheckRequest.java
new file mode 100644
index 0000000..27fec93
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCheckRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/env/check}.
+ */
+@Getter
+@Setter
+public class SparkEnvCheckRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String sparkName;
+
+    private String sparkHome;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCreateRequest.java
new file mode 100644
index 0000000..eb68124
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvCreateRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/env/create}, aligned with webapp {@code SparkCreate}.
+ */
+@Getter
+@Setter
+public class SparkEnvCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String sparkName;
+
+    @NotBlank
+    private String sparkHome;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvUpdateRequest.java
new file mode 100644
index 0000000..38ef038
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvUpdateRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Request body for {@code POST /spark/env/update}.
+ */
+@Getter
+@Setter
+public class SparkEnvUpdateRequest extends SparkEnvCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvValidityRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvValidityRequest.java
new file mode 100644
index 0000000..b1836ca
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkEnvValidityRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /spark/env/validity}.
+ */
+@Getter
+@Setter
+public class SparkEnvValidityRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineBuildRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineBuildRequest.java
new file mode 100644
index 0000000..8abc432
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineBuildRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/pipe/build}.
+ */
+@Getter
+@Setter
+public class SparkPipelineBuildRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+
+    private boolean forceBuild;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineDetailRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineDetailRequest.java
new file mode 100644
index 0000000..68a5979
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkPipelineDetailRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/pipe/detail}.
+ */
+@Getter
+@Setter
+public class SparkPipelineDetailRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long appId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlCompleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlCompleteRequest.java
new file mode 100644
index 0000000..1e8064f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlCompleteRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * Request body for {@code POST /spark/sql/sqlComplete}.
+ */
+@Getter
+@Setter
+public class SparkSqlCompleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private String sql;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlDeleteRequest.java
new file mode 100644
index 0000000..32cdc3e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlDeleteRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Request body for {@code POST /spark/sql/delete}.
+ */
+@Getter
+@Setter
+public class SparkSqlDeleteRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    /** Record id passed via the legacy {@code sql} form field. */
+    @NotBlank
+    private String sql;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlGetRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlGetRequest.java
new file mode 100644
index 0000000..b25fa8c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlGetRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Request body for {@code POST /spark/sql/get}.
+ */
+@Getter
+@Setter
+public class SparkSqlGetRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlHistoryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlHistoryRequest.java
new file mode 100644
index 0000000..4fa36bf
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlHistoryRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.AppScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Request body for {@code POST /spark/sql/history}.
+ */
+@Getter
+@Setter
+public class SparkSqlHistoryRequest extends AppScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlListQueryRequest.java
new file mode 100644
index 0000000..499a281
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlListQueryRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.AppTeamQueryRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Query filters for {@code POST /spark/sql/list}.
+ */
+@Getter
+@Setter
+public class SparkSqlListQueryRequest extends AppTeamQueryRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlVerifyRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlVerifyRequest.java
new file mode 100644
index 0000000..791972b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/spark/SparkSqlVerifyRequest.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 org.apache.streampark.console.core.request.spark;
+
+import org.apache.streampark.console.core.request.common.SqlVerifyRequest;
+
+/** Request body for {@code POST /spark/sql/verify}. */
+public class SparkSqlVerifyRequest extends SqlVerifyRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCheckCodeRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCheckCodeRequest.java
new file mode 100644
index 0000000..9a210b5
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCheckCodeRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.request.variable;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/** Request body for {@code POST /variable/check/code}. */
+@Getter
+@Setter
+public class VariableCheckCodeRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String variableCode;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCreateRequest.java
new file mode 100644
index 0000000..b069301
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableCreateRequest.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 org.apache.streampark.console.core.request.variable;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /variable/post}. */
+@Getter
+@Setter
+public class VariableCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    @NotBlank
+    private String variableCode;
+
+    @NotBlank
+    private String variableValue;
+
+    private String description;
+
+    private Boolean desensitization;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableListRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableListRequest.java
new file mode 100644
index 0000000..df8c980
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableListRequest.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 org.apache.streampark.console.core.request.variable;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /variable/list}. */
+@Getter
+@Setter
+public class VariableListRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String keyword;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariablePageQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariablePageQueryRequest.java
new file mode 100644
index 0000000..f6a45ad
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariablePageQueryRequest.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 org.apache.streampark.console.core.request.variable;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Query filters for {@code POST /variable/page}. */
+@Getter
+@Setter
+public class VariablePageQueryRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String variableCode;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableUpdateRequest.java
new file mode 100644
index 0000000..76d42a8
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/variable/VariableUpdateRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.variable;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code PUT /variable/update}. */
+@Getter
+@Setter
+public class VariableUpdateRequest extends VariableCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueCreateRequest.java
new file mode 100644
index 0000000..7d7ca92
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueCreateRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.request.yarn;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/** Request body for {@code POST /yarn/queue/create}. */
+@Getter
+@Setter
+public class YarnQueueCreateRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank
+    private String queueLabel;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueDeleteRequest.java
new file mode 100644
index 0000000..dac03da
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueDeleteRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.core.request.yarn;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /yarn/queue/delete}. */
+@Getter
+@Setter
+public class YarnQueueDeleteRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueListQueryRequest.java
new file mode 100644
index 0000000..fa19e13
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueListQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.request.yarn;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Query filters for {@code POST /yarn/queue/list}. */
+@Getter
+@Setter
+public class YarnQueueListQueryRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private String queueLabel;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueUpdateRequest.java
new file mode 100644
index 0000000..5d0b342
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/request/yarn/YarnQueueUpdateRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.request.yarn;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code POST /yarn/queue/update}. */
+@Getter
+@Setter
+public class YarnQueueUpdateRequest extends YarnQueueCreateRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/alert/AlertConfigResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/alert/AlertConfigResponse.java
new file mode 100644
index 0000000..36779b1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/alert/AlertConfigResponse.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.streampark.console.core.response.alert;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for an alert config, aligned with webapp {@code AlertSetting}. */
+@Getter
+@Setter
+public class AlertConfigResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long userId;
+
+    private String alertName;
+
+    private Integer alertType;
+
+    /** JSON string, aligned with legacy {@code AlertConfig} wire format. */
+    private String emailParams;
+
+    /** JSON string, aligned with legacy {@code AlertConfig} wire format. */
+    private String dingTalkParams;
+
+    /** JSON string, aligned with legacy {@code AlertConfig} wire format. */
+    private String weComParams;
+
+    /** JSON string, aligned with legacy {@code AlertConfig} wire format. */
+    private String httpCallbackParams;
+
+    /** JSON string, aligned with legacy {@code AlertConfig} wire format. */
+    private String larkParams;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppBackupResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppBackupResponse.java
new file mode 100644
index 0000000..7bdb073
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppBackupResponse.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.streampark.console.core.response.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Getter
+@Setter
+public class AppBackupResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Long sqlId;
+
+    private Long configId;
+
+    private String path;
+
+    private String description;
+
+    private Integer version;
+
+    private Date createTime;
+
+    private boolean backup;
+
+    private String teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppOptLogResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppOptLogResponse.java
new file mode 100644
index 0000000..608855f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/app/AppOptLogResponse.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.streampark.console.core.response.app;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Getter
+@Setter
+public class AppOptLogResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Integer jobType;
+
+    private String clusterId;
+
+    private String trackingUrl;
+
+    private Boolean success;
+
+    private Integer optionName;
+
+    private Date createTime;
+
+    private String exception;
+
+    private Long userId;
+
+    private String teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/externallink/ExternalLinkResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/externallink/ExternalLinkResponse.java
new file mode 100644
index 0000000..58f55cd
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/externallink/ExternalLinkResponse.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.streampark.console.core.response.externallink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for an external link, aligned with webapp {@code ExternalLink}. */
+@Getter
+@Setter
+public class ExternalLinkResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String badgeLabel;
+
+    private String badgeName;
+
+    private String badgeColor;
+
+    private String linkUrl;
+
+    private String renderedLinkUrl;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppDashboardResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppDashboardResponse.java
new file mode 100644
index 0000000..0f36358
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppDashboardResponse.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import org.apache.streampark.console.core.metrics.flink.JobsOverview;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * API response for {@code POST /flink/app/dashboard}, aligned with webapp {@code DashboardResponse}.
+ */
+@Getter
+@Setter
+public class FlinkAppDashboardResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private JobsOverview.Task task;
+
+    private Integer jmMemory;
+
+    private Integer tmMemory;
+
+    private Integer totalTM;
+
+    private Integer availableSlot;
+
+    private Integer totalSlot;
+
+    private Integer runningJob;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppResponse.java
new file mode 100644
index 0000000..f3411f2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkAppResponse.java
@@ -0,0 +1,216 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import org.apache.streampark.console.core.bean.AppControl;
+import org.apache.streampark.console.core.metrics.flink.JobsOverview;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink application, aligned with webapp {@code AppListRecord}.
+ */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class FlinkAppResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Integer jobType;
+
+    private Long projectId;
+
+    private String tags;
+
+    private Long userId;
+
+    private Long teamId;
+
+    private String jobName;
+
+    private String appId;
+
+    private String jobId;
+
+    private Long versionId;
+
+    private String clusterId;
+
+    private String flinkImage;
+
+    private String k8sNamespace;
+
+    private String serviceAccount;
+
+    private Integer state;
+
+    private Integer release;
+
+    private Boolean build;
+
+    private Integer restartSize;
+
+    private Integer restartCount;
+
+    private Integer optionState;
+
+    private Long alertId;
+
+    private String args;
+
+    private String module;
+
+    private String options;
+
+    private String hotParams;
+
+    private Integer resolveOrder;
+
+    private Integer deployMode;
+
+    private String dynamicProperties;
+
+    private Integer appType;
+
+    private Integer tracking;
+
+    private String jar;
+
+    private Long jarCheckSum;
+
+    private String mainClass;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Long duration;
+
+    private Integer cpMaxFailureInterval;
+
+    private Integer cpFailureRateInterval;
+
+    private Integer cpFailureAction;
+
+    private Integer totalTM;
+
+    private Integer totalSlot;
+
+    private Integer availableSlot;
+
+    private Integer jmMemory;
+
+    private Integer tmMemory;
+
+    private Integer totalTask;
+
+    private Long flinkClusterId;
+
+    private String description;
+
+    private Date createTime;
+
+    private Date optionTime;
+
+    private Date modifyTime;
+
+    private Integer resourceFrom;
+
+    private Integer k8sRestExposedType;
+
+    private String k8sPodTemplate;
+
+    private String k8sJmPodTemplate;
+
+    private String k8sTmPodTemplate;
+
+    private String ingressTemplate;
+
+    private String defaultModeIngress;
+
+    private Boolean k8sHadoopIntegration;
+
+    private JobsOverview.Task overview;
+
+    private String teamResource;
+
+    private String dependency;
+
+    private Long sqlId;
+
+    private String flinkSql;
+
+    private Integer[] stateArray;
+
+    private Integer[] jobTypeArray;
+
+    private Boolean backUp;
+
+    private Boolean restart;
+
+    private String userName;
+
+    private String nickName;
+
+    private String config;
+
+    private Long configId;
+
+    private String flinkVersion;
+
+    private String confPath;
+
+    private Integer format;
+
+    private String savepointPath;
+
+    private Boolean restoreOrTriggerSavepoint;
+
+    private Boolean drain;
+
+    private Boolean allowNonRestored;
+
+    private Boolean nativeFormat;
+
+    private String socketId;
+
+    private String projectName;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+
+    private String backUpDescription;
+
+    private String yarnQueue;
+
+    private String flinkRestUrl;
+
+    private Integer buildStatus;
+
+    private AppControl appControl;
+
+    private String hadoopUser;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterCheckResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterCheckResponse.java
new file mode 100644
index 0000000..daa8942
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterCheckResponse.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * API response for {@code POST /flink/cluster/check}.
+ */
+@Getter
+@Setter
+public class FlinkClusterCheckResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private int status;
+
+    private String msg;
+
+    private Serializable result;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterResponse.java
new file mode 100644
index 0000000..ba9f5a5
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkClusterResponse.java
@@ -0,0 +1,88 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink cluster, aligned with webapp {@code FlinkCluster}.
+ */
+@Getter
+@Setter
+public class FlinkClusterResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String address;
+
+    private String jobManagerUrl;
+
+    private String clusterId;
+
+    private String clusterName;
+
+    private Integer deployMode;
+
+    private Long versionId;
+
+    private String k8sNamespace;
+
+    private String serviceAccount;
+
+    private String description;
+
+    private Long userId;
+
+    private String flinkImage;
+
+    private String options;
+
+    private String yarnQueue;
+
+    private Boolean k8sHadoopIntegration;
+
+    private String dynamicProperties;
+
+    private Integer k8sRestExposedType;
+
+    private String k8sConf;
+
+    private Integer resolveOrder;
+
+    private String exception;
+
+    private Integer clusterState;
+
+    private Date createTime;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Long alertId;
+
+    private Integer allJobs;
+
+    private Integer affectedJobs;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfHadoopResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfHadoopResponse.java
new file mode 100644
index 0000000..a8def51
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfHadoopResponse.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * API response for {@code POST /flink/conf/sys_hadoop_conf}.
+ */
+@Getter
+@Setter
+public class FlinkConfHadoopResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Map<String, String> hadoop;
+
+    private Map<String, String> hive;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfResponse.java
new file mode 100644
index 0000000..f639861
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkConfResponse.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink application configuration version.
+ */
+@Getter
+@Setter
+public class FlinkConfResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Integer format;
+
+    private Integer version;
+
+    private String content;
+
+    private Date createTime;
+
+    private Boolean latest;
+
+    private boolean effective;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkEnvResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkEnvResponse.java
new file mode 100644
index 0000000..f57e79c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkEnvResponse.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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink environment, aligned with webapp {@code FlinkEnv}.
+ */
+@Getter
+@Setter
+public class FlinkEnvResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String flinkName;
+
+    private String flinkHome;
+
+    private String flinkConf;
+
+    private String description;
+
+    private String scalaVersion;
+
+    private String version;
+
+    private Boolean isDefault;
+
+    private Date createTime;
+
+    private String versionOfLarge;
+
+    private String versionOfMiddle;
+
+    private String versionOfLast;
+
+    private String streamParkScalaVersion;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkPipelineDetailResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkPipelineDetailResponse.java
new file mode 100644
index 0000000..07dd278
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkPipelineDetailResponse.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import org.apache.streampark.console.core.bean.AppBuildDockerResolvedDetail;
+import org.apache.streampark.console.core.entity.ApplicationBuildPipeline;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * API response for {@code POST /flink/pipe/detail}.
+ */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class FlinkPipelineDetailResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private ApplicationBuildPipeline.View pipeline;
+
+    private AppBuildDockerResolvedDetail docker;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkSqlResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkSqlResponse.java
new file mode 100644
index 0000000..afba49b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/FlinkSqlResponse.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink SQL version record.
+ */
+@Getter
+@Setter
+public class FlinkSqlResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private String sql;
+
+    private String teamResource;
+
+    private String dependency;
+
+    private Integer version;
+
+    private Integer candidate;
+
+    private Date createTime;
+
+    private boolean effective;
+
+    private boolean sqlDifference;
+
+    private boolean dependencyDifference;
+
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/SavepointResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/SavepointResponse.java
new file mode 100644
index 0000000..defdd83
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/flink/SavepointResponse.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.core.response.flink;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Flink savepoint record.
+ */
+@Getter
+@Setter
+public class SavepointResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Long chkId;
+
+    private Boolean latest;
+
+    private Integer type;
+
+    private String path;
+
+    private Date triggerTime;
+
+    private Date createTime;
+
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/message/MessageResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/message/MessageResponse.java
new file mode 100644
index 0000000..77467ac
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/message/MessageResponse.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.streampark.console.core.response.message;
+
+import org.apache.streampark.console.core.enums.NoticeTypeEnum;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for a message, aligned with webapp {@code NotifyItem}. */
+@Getter
+@Setter
+public class MessageResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Long userId;
+
+    private String title;
+
+    private NoticeTypeEnum type;
+
+    private String context;
+
+    private Boolean isRead;
+
+    private Date createTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBranchesResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBranchesResponse.java
new file mode 100644
index 0000000..7ff925c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBranchesResponse.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.response.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/** Response for {@code POST /project/branches}. */
+@Getter
+@Setter
+public class ProjectBranchesResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<String> tags;
+
+    private List<String> branches;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBuildLogResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBuildLogResponse.java
new file mode 100644
index 0000000..6d0d9fc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectBuildLogResponse.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.response.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Build log payload for project build progress polling. */
+@Getter
+@Setter
+public class ProjectBuildLogResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String logContent;
+
+    private Long offset;
+
+    private Boolean readFinished;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectResponse.java
new file mode 100644
index 0000000..483e6e4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/project/ProjectResponse.java
@@ -0,0 +1,72 @@
+/*
+ * 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 org.apache.streampark.console.core.response.project;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for a project, aligned with webapp {@code ProjectRecord}. */
+@Getter
+@Setter
+public class ProjectResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private String name;
+
+    private String url;
+
+    private String refs;
+
+    private Date lastBuild;
+
+    private String userName;
+
+    private String password;
+
+    private String prvkeyPath;
+
+    private Integer repository;
+
+    private String pom;
+
+    private String buildArgs;
+
+    private String description;
+
+    private Integer buildState;
+
+    private Integer type;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private String module;
+
+    private String dateFrom;
+
+    private String dateTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceCheckResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceCheckResponse.java
new file mode 100644
index 0000000..559bba7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceCheckResponse.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.response.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Result of resource validation (connector / application jar check). */
+@Getter
+@Setter
+public class ResourceCheckResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Integer state;
+
+    private String exception;
+
+    private String connector;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceResponse.java
new file mode 100644
index 0000000..022db6c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceResponse.java
@@ -0,0 +1,64 @@
+/*
+ * 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 org.apache.streampark.console.core.response.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for a resource, aligned with webapp {@code ResourceListRecord}. */
+@Getter
+@Setter
+public class ResourceResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String resourceName;
+
+    private String resourcePath;
+
+    private String resource;
+
+    private String description;
+
+    private Long creatorId;
+
+    private String creatorName;
+
+    private String resourceType;
+
+    private String engineType;
+
+    private String mainClass;
+
+    private String connectorRequiredOptions;
+
+    private String connectorOptionalOptions;
+
+    private Long teamId;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private String connector;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceUploadResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceUploadResponse.java
new file mode 100644
index 0000000..6224110
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/resource/ResourceUploadResponse.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.response.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Response for {@code POST /resource/upload}. */
+@Getter
+@Setter
+public class ResourceUploadResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String path;
+
+    private String mainClass;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingCheckResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingCheckResponse.java
new file mode 100644
index 0000000..eb80f7c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingCheckResponse.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.response.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** API response for setting connectivity check results. */
+@Getter
+@Setter
+public class SettingCheckResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private int status;
+
+    private String msg;
+
+    private Serializable result;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingDockerResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingDockerResponse.java
new file mode 100644
index 0000000..201893e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingDockerResponse.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.core.response.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** API response for docker registry settings. */
+@Getter
+@Setter
+public class SettingDockerResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String address;
+
+    private String username;
+
+    private String password;
+
+    private String namespace;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingEmailResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingEmailResponse.java
new file mode 100644
index 0000000..a6b8007
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingEmailResponse.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.core.response.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** API response for sender email settings. */
+@Getter
+@Setter
+public class SettingEmailResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String host;
+
+    private Integer port;
+
+    private String from;
+
+    private String userName;
+
+    private String password;
+
+    private boolean ssl;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingResponse.java
new file mode 100644
index 0000000..ee55dec
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/setting/SettingResponse.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.streampark.console.core.response.setting;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** API response for a system setting, aligned with webapp {@code SystemSetting}. */
+@Getter
+@Setter
+public class SettingResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Integer orderNum;
+
+    private String settingName;
+
+    private String settingKey;
+
+    private String settingValue;
+
+    private Integer type;
+
+    private String description;
+
+    private boolean editable;
+
+    private boolean submitting;
+
+    private String flinkHome;
+
+    private String flinkConf;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppDashboardResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppDashboardResponse.java
new file mode 100644
index 0000000..5775716
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppDashboardResponse.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 org.apache.streampark.console.core.response.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * API response for {@code POST /spark/app/dashboard}, aligned with webapp {@code DashboardResponse}.
+ */
+@Getter
+@Setter
+public class SparkAppDashboardResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Integer runningApplication;
+
+    private Long numTasks;
+
+    private Long numCompletedTasks;
+
+    private Long numStages;
+
+    private Long numCompletedStages;
+
+    private Long usedMemory;
+
+    private Long usedVCores;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppResponse.java
new file mode 100644
index 0000000..3d3c2f4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkAppResponse.java
@@ -0,0 +1,185 @@
+/*
+ * 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 org.apache.streampark.console.core.response.spark;
+
+import org.apache.streampark.console.core.bean.AppControl;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Spark application, aligned with webapp {@code SparkApplication}.
+ */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class SparkAppResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private Integer jobType;
+
+    private Integer appType;
+
+    private Long versionId;
+
+    private String appName;
+
+    private Integer deployMode;
+
+    private Integer resourceFrom;
+
+    private Long projectId;
+
+    private String module;
+
+    private String mainClass;
+
+    private String jar;
+
+    private Long jarCheckSum;
+
+    private String appProperties;
+
+    private String appArgs;
+
+    private String clusterId;
+
+    private String yarnQueue;
+
+    private String yarnQueueName;
+
+    private String yarnQueueLabel;
+
+    private String k8sMasterUrl;
+
+    private String k8sContainerImage;
+
+    private Integer k8sImagePullPolicy;
+
+    private String k8sServiceAccount;
+
+    private String k8sNamespace;
+
+    private String k8sDriverPodTemplate;
+
+    private String k8sExecutorPodTemplate;
+
+    private Boolean k8sHadoopIntegration;
+
+    private String hadoopUser;
+
+    private Integer restartSize;
+
+    private Integer restartCount;
+
+    private Integer state;
+
+    private String options;
+
+    private Integer optionState;
+
+    private Date optionTime;
+
+    private Long userId;
+
+    private String description;
+
+    private Integer tracking;
+
+    private Integer release;
+
+    private Boolean build;
+
+    private Long alertId;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Long duration;
+
+    private String tags;
+
+    private String driverCores;
+
+    private String driverMemory;
+
+    private String executorCores;
+
+    private String executorMemory;
+
+    private String executorMaxNums;
+
+    private Long numTasks;
+
+    private Long numCompletedTasks;
+
+    private Long numStages;
+
+    private Long numCompletedStages;
+
+    private Long usedMemory;
+
+    private Long usedVCores;
+
+    private String teamResource;
+
+    private String dependency;
+
+    private Long sqlId;
+
+    private String sparkSql;
+
+    private Boolean backUp;
+
+    private Boolean restart;
+
+    private String config;
+
+    private Long configId;
+
+    private String sparkVersion;
+
+    private String confPath;
+
+    private Integer format;
+
+    private String backUpDescription;
+
+    private String sparkRestUrl;
+
+    private Integer buildStatus;
+
+    private AppControl appControl;
+
+    private String userName;
+
+    private String nickName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkConfResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkConfResponse.java
new file mode 100644
index 0000000..848acb9
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkConfResponse.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.streampark.console.core.response.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Spark application config, aligned with webapp {@code SparkApplicationConfig}.
+ */
+@Getter
+@Setter
+public class SparkConfResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private Integer format;
+
+    private String content;
+
+    private Integer version;
+
+    private Boolean latest;
+
+    private Date createTime;
+
+    private Boolean effective;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkEnvResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkEnvResponse.java
new file mode 100644
index 0000000..210fa4e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkEnvResponse.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.response.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Spark environment, aligned with webapp {@code SparkEnv}.
+ */
+@Getter
+@Setter
+public class SparkEnvResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String sparkName;
+
+    private String sparkHome;
+
+    private String sparkConf;
+
+    private String description;
+
+    private String scalaVersion;
+
+    private String version;
+
+    private Boolean isDefault;
+
+    private Date createTime;
+
+    private String streamParkScalaVersion;
+
+    private String versionOfMiddle;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkPipelineDetailResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkPipelineDetailResponse.java
new file mode 100644
index 0000000..2e123c5
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkPipelineDetailResponse.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.core.response.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * API response for {@code POST /spark/pipe/detail}, aligned with webapp build progress detail.
+ */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class SparkPipelineDetailResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Object pipeline;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkSqlResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkSqlResponse.java
new file mode 100644
index 0000000..0da74f1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/spark/SparkSqlResponse.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.response.spark;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a Spark SQL record, aligned with webapp {@code SparkSql}.
+ */
+@Getter
+@Setter
+public class SparkSqlResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long appId;
+
+    private String sql;
+
+    private String teamResource;
+
+    private String dependency;
+
+    private Integer version;
+
+    private Integer candidate;
+
+    private Date createTime;
+
+    private Boolean effective;
+
+    private Boolean sqlDifference;
+
+    private Boolean dependencyDifference;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/sql/SqlCompleteResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/sql/SqlCompleteResponse.java
new file mode 100644
index 0000000..0e2baab
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/sql/SqlCompleteResponse.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.core.response.sql;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/** API response for SQL editor autocomplete ({@code POST /flink/sql/sql_complete}). */
+@Getter
+@Setter
+public class SqlCompleteResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<String> word;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/variable/VariableResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/variable/VariableResponse.java
new file mode 100644
index 0000000..aa0aab6
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/variable/VariableResponse.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.core.response.variable;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for a variable, aligned with webapp {@code VariableListRecord}. */
+@Getter
+@Setter
+public class VariableResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String variableCode;
+
+    private String variableValue;
+
+    private String description;
+
+    private Long creatorId;
+
+    private String creatorName;
+
+    private Long teamId;
+
+    private Boolean desensitization;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueCheckResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueCheckResponse.java
new file mode 100644
index 0000000..af0d916
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueCheckResponse.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.core.response.yarn;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** API response for {@code POST /yarnQueue/check}. */
+@Getter
+@Setter
+public class YarnQueueCheckResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private int status;
+
+    private String msg;
+
+    private String result;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueResponse.java
new file mode 100644
index 0000000..9f61734
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/response/yarn/YarnQueueResponse.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 org.apache.streampark.console.core.response.yarn;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** API response for a yarn queue, aligned with webapp {@code YarnQueue}. */
+@Getter
+@Setter
+public class YarnQueueResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private String queueLabel;
+
+    private String description;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ProjectService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ProjectService.java
index 206c840..a31df84 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ProjectService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ProjectService.java
@@ -18,10 +18,10 @@
 package org.apache.streampark.console.core.service;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.entity.Project;
 import org.apache.streampark.console.core.enums.GitAuthorizedErrorEnum;
+import org.apache.streampark.console.core.service.result.ProjectBuildLogResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
@@ -35,9 +35,9 @@
      * Create a new instance.
      *
      * @param project Project to be created
-     * @return RestResponse
+     * @return whether the create is successful
      */
-    RestResponse create(Project project);
+    boolean create(Project project);
 
     boolean checkExists(Project project);
 
@@ -96,9 +96,9 @@
      *
      * @param id Project id
      * @param startOffset startOffset
-     * @return RestResponse
+     * @return build log content with optional offset/readFinished metadata
      */
-    RestResponse getBuildLog(Long id, Long startOffset);
+    ProjectBuildLogResult getBuildLog(Long id, Long startOffset);
 
     /**
      * List all modules of the specified project
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
index 319da76..7a4c439 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
@@ -18,9 +18,9 @@
 package org.apache.streampark.console.core.service;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.core.bean.UploadResponse;
 import org.apache.streampark.console.core.entity.Resource;
+import org.apache.streampark.console.core.service.result.ResourceCheckResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
@@ -94,7 +94,7 @@
 
     UploadResponse upload(MultipartFile file) throws IOException;
 
-    RestResponse checkResource(Resource resource) throws Exception;
+    ResourceCheckResult checkResource(Resource resource) throws Exception;
 
     /**
      * Uploads a list of jars to the server for historical reference.
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertConfigService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertConfigService.java
index 37a62f4..bf29064 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertConfigService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertConfigService.java
@@ -19,7 +19,6 @@
 
 import org.apache.streampark.console.base.domain.RestRequest;
 import org.apache.streampark.console.base.exception.AlertException;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.entity.AlertConfig;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -29,13 +28,13 @@
 public interface AlertConfigService extends IService<AlertConfig> {
 
     /**
-     * Retrieves a page of {@link AlertConfigParams} objects based on the provided parameters.
+     * Retrieves a page of alert configs based on the provided parameters.
      *
      * @param userId user id.
      * @param request The {@link RestRequest} object used for pagination and sorting.
-     * @return An {@link IPage} containing the retrieved {@link AlertConfigParams} objects.
+     * @return An {@link IPage} containing the retrieved alert configs.
      */
-    IPage<AlertConfigParams> page(Long userId, RestRequest request);
+    IPage<AlertConfig> pageEntities(Long userId, RestRequest request);
 
     /**
      * check whether the relevant alarm configuration exists
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertNotifyService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertNotifyService.java
index f9b9e27..9fc59bf 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertNotifyService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/AlertNotifyService.java
@@ -18,8 +18,8 @@
 package org.apache.streampark.console.core.service.alert;
 
 import org.apache.streampark.console.base.exception.AlertException;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 
 /**
  * This interface defines a service for sending alert notifications, it has multiple
@@ -35,5 +35,5 @@
      * @return true if the alert was successfully triggered, false otherwise.
      * @throws AlertException if an error occurs while performing the alert.
      */
-    boolean doAlert(AlertConfigParams alertConfig, AlertTemplate template) throws AlertException;
+    boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate template) throws AlertException;
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertConfigServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertConfigServiceImpl.java
index f6dcaf7..f4e76b2 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertConfigServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertConfigServiceImpl.java
@@ -20,15 +20,12 @@
 import org.apache.streampark.console.base.domain.RestRequest;
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.mybatis.pager.MybatisPager;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.entity.AlertConfig;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.mapper.AlertConfigMapper;
 import org.apache.streampark.console.core.service.alert.AlertConfigService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationInfoService;
 
-import org.apache.commons.collections.CollectionUtils;
-
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -39,8 +36,6 @@
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.stream.Collectors;
-
 @Service
 @Slf4j
 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
@@ -52,18 +47,9 @@
     private FlinkApplicationInfoService applicationInfoService;
 
     @Override
-    public IPage<AlertConfigParams> page(Long userId, RestRequest request) {
-        // build query conditions
+    public IPage<AlertConfig> pageEntities(Long userId, RestRequest request) {
         Page<AlertConfig> page = MybatisPager.getPage(request);
-        IPage<AlertConfig> resultPage =
-            this.lambdaQuery().eq(userId != null, AlertConfig::getUserId, userId).page(page);
-        Page<AlertConfigParams> result = new Page<>();
-        if (CollectionUtils.isNotEmpty(resultPage.getRecords())) {
-            result.setRecords(
-                resultPage.getRecords().stream().map(AlertConfigParams::of).collect(Collectors.toList()));
-        }
-
-        return result;
+        return this.lambdaQuery().eq(userId != null, AlertConfig::getUserId, userId).page(page);
     }
 
     @Override
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertServiceImpl.java
index bca40e1..6e72dc4 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/AlertServiceImpl.java
@@ -19,10 +19,11 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.SpringContextUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
+import org.apache.streampark.console.core.assembler.AlertAssembler;
 import org.apache.streampark.console.core.bean.AlertTemplate;
 import org.apache.streampark.console.core.entity.AlertConfig;
 import org.apache.streampark.console.core.enums.AlertTypeEnum;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertConfigService;
 import org.apache.streampark.console.core.service.alert.AlertService;
 
@@ -53,7 +54,7 @@
         }
         AlertConfig alertConfig = alertConfigService.getById(alertConfigId);
         try {
-            AlertConfigParams params = AlertConfigParams.of(alertConfig);
+            AlertConfigRequest params = AlertAssembler.toRequest(alertConfig);
             List<AlertTypeEnum> alertTypeEnums = AlertTypeEnum.decode(params.getAlertType());
             if (CollectionUtils.isEmpty(alertTypeEnums)) {
                 return true;
@@ -74,7 +75,8 @@
     @Nonnull
     private Tuple2<Boolean, AlertException> triggerAlert(
                                                          AlertTemplate alertTemplate,
-                                                         List<AlertTypeEnum> alertTypeEnums, AlertConfigParams params) {
+                                                         List<AlertTypeEnum> alertTypeEnums,
+                                                         AlertConfigRequest params) {
         return alertTypeEnums.stream()
             .map(
                 alertTypeEnum -> {
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/DingTalkAlertNotifyServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/DingTalkAlertNotifyServiceImpl.java
index ca2a5d8..91c1bc6 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/DingTalkAlertNotifyServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/DingTalkAlertNotifyServiceImpl.java
@@ -19,10 +19,10 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertDingTalkParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
 import org.apache.streampark.console.core.bean.RobotResponse;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertNotifyService;
 
 import org.apache.commons.lang3.BooleanUtils;
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public boolean doAlert(AlertConfigParams alertConfig, AlertTemplate alertTemplate) throws AlertException {
+    public boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate alertTemplate) throws AlertException {
         AlertDingTalkParams dingTalkParams = alertConfig.getDingTalkParams();
         try {
             // handling contacts
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/EmailAlertNotifyServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/EmailAlertNotifyServiceImpl.java
index b3904dd..aa30eba 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/EmailAlertNotifyServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/EmailAlertNotifyServiceImpl.java
@@ -19,9 +19,9 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
 import org.apache.streampark.console.core.bean.EmailConfig;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertNotifyService;
 
 import org.apache.commons.mail.HtmlEmail;
@@ -44,7 +44,7 @@
     private final Template template = FreemarkerUtils.loadTemplateFile("alert-email.ftl");
 
     @Override
-    public boolean doAlert(AlertConfigParams alertConfig, AlertTemplate template) throws AlertException {
+    public boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate template) throws AlertException {
         EmailConfig emailConfig = Optional.ofNullable(EmailConfig.fromSetting())
             .orElseThrow(() -> new AlertException("Please configure the email sender first"));
         String contacts = alertConfig.getEmailParams() == null ? null : alertConfig.getEmailParams().getContacts();
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/HttpCallbackAlertNotifyServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/HttpCallbackAlertNotifyServiceImpl.java
index 084dc49..37ee6c5 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/HttpCallbackAlertNotifyServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/HttpCallbackAlertNotifyServiceImpl.java
@@ -19,9 +19,9 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertHttpCallbackParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertNotifyService;
 
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -57,7 +57,7 @@
     private ObjectMapper mapper;
 
     @Override
-    public boolean doAlert(AlertConfigParams alertConfig, AlertTemplate alertTemplate) throws AlertException {
+    public boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate alertTemplate) throws AlertException {
         AlertHttpCallbackParams alertHttpCallbackParams = alertConfig.getHttpCallbackParams();
 
         String requestTemplate = alertHttpCallbackParams.getRequestTemplate();
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/LarkAlertNotifyServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/LarkAlertNotifyServiceImpl.java
index ecc4a95..4483c9c 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/LarkAlertNotifyServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/LarkAlertNotifyServiceImpl.java
@@ -19,10 +19,10 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertLarkParams;
 import org.apache.streampark.console.core.bean.AlertLarkRobotResponse;
 import org.apache.streampark.console.core.bean.AlertTemplate;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertNotifyService;
 
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public boolean doAlert(AlertConfigParams alertConfig, AlertTemplate alertTemplate) throws AlertException {
+    public boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate alertTemplate) throws AlertException {
         AlertLarkParams alertLarkParams = alertConfig.getLarkParams();
         if (alertLarkParams.getIsAtAll()) {
             alertTemplate.setAtAll(true);
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/WeComAlertNotifyServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/WeComAlertNotifyServiceImpl.java
index 650e0cc..1a4715d 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/WeComAlertNotifyServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/alert/impl/WeComAlertNotifyServiceImpl.java
@@ -19,10 +19,10 @@
 
 import org.apache.streampark.console.base.exception.AlertException;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
 import org.apache.streampark.console.core.bean.AlertWeComParams;
 import org.apache.streampark.console.core.bean.RobotResponse;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.AlertNotifyService;
 
 import freemarker.template.Template;
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public boolean doAlert(AlertConfigParams alertConfig, AlertTemplate alertTemplate) throws AlertException {
+    public boolean doAlert(AlertConfigRequest alertConfig, AlertTemplate alertTemplate) throws AlertException {
         AlertWeComParams weComParams = alertConfig.getWeComParams();
         try {
             // format markdown
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ProjectServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ProjectServiceImpl.java
index 220f8d1..ff89feb 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ProjectServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ProjectServiceImpl.java
@@ -24,9 +24,7 @@
 import org.apache.streampark.common.util.AssertUtils;
 import org.apache.streampark.common.util.CompletableFutureUtils;
 import org.apache.streampark.common.util.FileUtils;
-import org.apache.streampark.console.base.domain.ResponseCode;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.exception.ApiDetailException;
 import org.apache.streampark.console.base.mybatis.pager.MybatisPager;
@@ -40,6 +38,7 @@
 import org.apache.streampark.console.core.mapper.ProjectMapper;
 import org.apache.streampark.console.core.service.ProjectService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationManageService;
+import org.apache.streampark.console.core.service.result.ProjectBuildLogResult;
 import org.apache.streampark.console.core.task.ProjectBuildTask;
 import org.apache.streampark.console.core.watcher.FlinkAppHttpWatcher;
 
@@ -98,20 +97,14 @@
     private Long maxProjectBuildNum;
 
     @Override
-    public RestResponse create(Project project) {
-        RestResponse response = RestResponse.success();
+    public boolean create(Project project) {
         project.setId(null);
         ApiAlertException.throwIfTrue(
             checkExists(project), "project name already exists, add project failed");
         Date date = new Date();
         project.setCreateTime(date);
         project.setModifyTime(date);
-        boolean status = save(project);
-        if (status) {
-            return response.message("Add project successfully").data(true);
-        } else {
-            return response.message("Add project failed").data(false);
-        }
+        return save(project);
     }
 
     @Override
@@ -364,18 +357,19 @@
     }
 
     @Override
-    public RestResponse getBuildLog(Long id, Long startOffset) {
+    public ProjectBuildLogResult getBuildLog(Long id, Long startOffset) {
         File logFile = Paths.get(getBuildLogPath(id)).toFile();
+        ProjectBuildLogResult result = new ProjectBuildLogResult();
         if (!logFile.exists()) {
             String errorMsg = String.format("Build log file(fileName=%s) not found, please build first.", logFile);
             log.warn(errorMsg);
-            return RestResponse.success().data(errorMsg);
+            result.setContent(errorMsg);
+            return result;
         }
         boolean isBuilding = this.getById(id).getBuildState() == 0;
         byte[] fileContent;
-        long endOffset = 0L;
-        boolean readFinished = true;
-        // Read log from earliest when project is building
+        Long endOffset = null;
+        Boolean readFinished = null;
         if (startOffset == null && isBuilding) {
             startOffset = 0L;
         }
@@ -388,14 +382,16 @@
                 endOffset = startOffset + fileContent.length;
                 readFinished = logFile.length() == endOffset && !isBuilding;
             }
-            return RestResponse.success()
-                .data(new String(fileContent, StandardCharsets.UTF_8))
-                .put("offset", endOffset)
-                .put("readFinished", readFinished);
+            result.setContent(new String(fileContent, StandardCharsets.UTF_8));
+            result.setOffset(endOffset);
+            result.setReadFinished(readFinished);
+            return result;
         } catch (IOException e) {
             String error = String.format("Read build log file(fileName=%s) caused an exception: ", logFile);
             log.error(error, e);
-            return RestResponse.fail(ResponseCode.CODE_FAIL, error + e.getMessage());
+            result.setFailed(true);
+            result.setContent(error + e.getMessage());
+            return result;
         }
     }
 
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
index b0139f7..e4f1bd4 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
@@ -24,7 +24,6 @@
 import org.apache.streampark.common.util.ExceptionUtils;
 import org.apache.streampark.common.util.Utils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.exception.ApiDetailException;
 import org.apache.streampark.console.base.mybatis.pager.MybatisPager;
@@ -42,6 +41,7 @@
 import org.apache.streampark.console.core.service.FlinkSqlService;
 import org.apache.streampark.console.core.service.ResourceService;
 import org.apache.streampark.console.core.service.application.FlinkApplicationManageService;
+import org.apache.streampark.console.core.service.result.ResourceCheckResult;
 import org.apache.streampark.console.core.util.ServiceHelper;
 import org.apache.streampark.flink.packer.maven.Artifact;
 import org.apache.streampark.flink.packer.maven.MavenTool;
@@ -57,7 +57,6 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.common.collect.ImmutableMap;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -69,7 +68,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.Serializable;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.time.Duration;
@@ -288,15 +286,16 @@
     }
 
     @Override
-    public RestResponse checkResource(Resource resourceParam) throws JsonProcessingException {
+    public ResourceCheckResult checkResource(Resource resourceParam) throws JsonProcessingException {
         ResourceTypeEnum type = resourceParam.getResourceType();
         switch (type) {
             case APP:
                 return checkFlinkApp(resourceParam);
             case CONNECTOR:
                 return checkConnector(resourceParam);
+            default:
+                return okCheck(0, null, null);
         }
-        return RestResponse.success().data(ImmutableMap.of(STATE, 0));
     }
 
     @Override
@@ -309,7 +308,7 @@
             .collect(Collectors.toList());
     }
 
-    private RestResponse checkConnector(Resource resourceParam) throws JsonProcessingException {
+    private ResourceCheckResult checkConnector(Resource resourceParam) throws JsonProcessingException {
         // 1) get connector jar
         FlinkConnector connectorResource;
         List<File> jars;
@@ -352,16 +351,14 @@
             return buildExceptResponse(
                 new RuntimeException("resource name different with FactoryIdentifier"), 5);
         }
-        return RestResponse.success()
-            .data(ImmutableMap.of(STATE, 0, "connector", JacksonUtils.write(connectorResource)));
+        return okCheck(0, null, JacksonUtils.write(connectorResource));
     }
 
-    private static RestResponse buildExceptResponse(Exception e, int code) {
-        return RestResponse.success()
-            .data(ImmutableMap.of(STATE, code, EXCEPTION, ExceptionUtils.stringifyException(e)));
+    private static ResourceCheckResult buildExceptResponse(Exception e, int code) {
+        return okCheck(code, ExceptionUtils.stringifyException(e), null);
     }
 
-    private RestResponse checkFlinkApp(Resource resourceParam) {
+    private ResourceCheckResult checkFlinkApp(Resource resourceParam) {
         // check main.
         File jarFile;
         try {
@@ -372,9 +369,18 @@
         }
         ApiAlertException.throwIfTrue(
             jarFile == null || !jarFile.exists(), "flink app jar must exist.");
-        Map<String, Serializable> resp = new HashMap<>(0);
-        resp.put(STATE, 0);
-        return RestResponse.success().data(resp);
+        return okCheck(0, null, null);
+    }
+
+    private static ResourceCheckResult okCheck(
+                                               Integer state,
+                                               String exception,
+                                               String connector) {
+        ResourceCheckResult result = new ResourceCheckResult();
+        result.setState(state);
+        result.setException(exception);
+        result.setConnector(connector);
+        return result;
     }
 
     private boolean existsFlinkConnector(Long id, String connectorId) {
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ProjectBuildLogResult.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ProjectBuildLogResult.java
new file mode 100644
index 0000000..242be23
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ProjectBuildLogResult.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.core.service.result;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Service-layer result for project build log polling. */
+@Getter
+@Setter
+public class ProjectBuildLogResult {
+
+    private String content;
+
+    private Long offset;
+
+    private Boolean readFinished;
+
+    private boolean failed;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ResourceCheckResult.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ResourceCheckResult.java
new file mode 100644
index 0000000..84ffca7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/result/ResourceCheckResult.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 org.apache.streampark.console.core.service.result;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Service-layer result for resource validation. */
+@Getter
+@Setter
+public class ResourceCheckResult {
+
+    private Integer state;
+
+    private String exception;
+
+    private String connector;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/AccessTokenAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/AccessTokenAssembler.java
new file mode 100644
index 0000000..15397ff
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/AccessTokenAssembler.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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.AccessToken;
+import org.apache.streampark.console.system.request.token.TokenListQueryRequest;
+import org.apache.streampark.console.system.response.token.AccessTokenResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/** Converts between access-token entities and API request/response contracts. */
+public final class AccessTokenAssembler {
+
+    private AccessTokenAssembler() {
+    }
+
+    public static AccessToken toEntity(TokenListQueryRequest request) {
+        return DtoAssembler.toDto(request, AccessToken.class);
+    }
+
+    public static AccessTokenResponse toResponse(AccessToken token) {
+        return DtoAssembler.toDto(token, AccessTokenResponse.class);
+    }
+
+    public static IPage<AccessTokenResponse> toPageResponse(IPage<AccessToken> page) {
+        return DtoAssembler.toPage(page, AccessTokenAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MemberAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MemberAssembler.java
new file mode 100644
index 0000000..7e6bb3e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MemberAssembler.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.Member;
+import org.apache.streampark.console.system.request.member.MemberCreateRequest;
+import org.apache.streampark.console.system.request.member.MemberListQueryRequest;
+import org.apache.streampark.console.system.request.member.MemberUpdateRequest;
+import org.apache.streampark.console.system.response.member.MemberResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/** Converts between member entities and API request/response contracts. */
+public final class MemberAssembler {
+
+    private MemberAssembler() {
+    }
+
+    public static Member toEntity(MemberListQueryRequest request) {
+        return DtoAssembler.toDto(request, Member.class);
+    }
+
+    public static Member toEntity(MemberCreateRequest request) {
+        return DtoAssembler.toDto(request, Member.class);
+    }
+
+    public static Member toEntity(MemberUpdateRequest request) {
+        return DtoAssembler.toDto(request, Member.class);
+    }
+
+    public static MemberResponse toResponse(Member member) {
+        return DtoAssembler.toDto(member, MemberResponse.class);
+    }
+
+    public static IPage<MemberResponse> toPageResponse(IPage<Member> page) {
+        return DtoAssembler.toPage(page, MemberAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MenuAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MenuAssembler.java
new file mode 100644
index 0000000..c5b1e57
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/MenuAssembler.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.Menu;
+import org.apache.streampark.console.system.request.menu.MenuListQueryRequest;
+import org.apache.streampark.console.system.response.menu.MenuListResponse;
+import org.apache.streampark.console.system.service.impl.MenuServiceImpl;
+
+import java.util.List;
+import java.util.Map;
+
+/** Converts between menu entities and API request/response contracts. */
+public final class MenuAssembler {
+
+    private MenuAssembler() {
+    }
+
+    public static Menu toEntity(MenuListQueryRequest request) {
+        return DtoAssembler.toDto(request, Menu.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static MenuListResponse toListResponse(Map<String, Object> menuMap) {
+        if (menuMap == null) {
+            return null;
+        }
+        MenuListResponse response = new MenuListResponse();
+        response.setIds((List<String>) menuMap.get(MenuServiceImpl.IDS));
+        Object total = menuMap.get(MenuServiceImpl.TOTAL);
+        if (total instanceof Integer) {
+            response.setTotal((Integer) total);
+        } else if (total instanceof Long) {
+            response.setTotal(((Long) total).intValue());
+        }
+        response.setRows(
+            (org.apache.streampark.console.base.domain.router.RouterTree<?>) menuMap.get(MenuServiceImpl.ROWS));
+        return response;
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/PassportAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/PassportAssembler.java
new file mode 100644
index 0000000..1353594
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/PassportAssembler.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.enums.LoginTypeEnum;
+import org.apache.streampark.console.system.request.passport.PassportSignInRequest;
+
+/** Converts passport request contracts to domain values. */
+public final class PassportAssembler {
+
+    private PassportAssembler() {
+    }
+
+    public static LoginTypeEnum toLoginType(PassportSignInRequest request) {
+        if (request == null || request.getLoginType() == null) {
+            return null;
+        }
+        return LoginTypeEnum.of(request.getLoginType());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/RoleAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/RoleAssembler.java
new file mode 100644
index 0000000..b188c51
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/RoleAssembler.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.Role;
+import org.apache.streampark.console.system.request.role.RoleCreateRequest;
+import org.apache.streampark.console.system.request.role.RoleListQueryRequest;
+import org.apache.streampark.console.system.request.role.RoleUpdateRequest;
+import org.apache.streampark.console.system.response.role.RoleResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/** Converts between role entities and API request/response contracts. */
+public final class RoleAssembler {
+
+    private RoleAssembler() {
+    }
+
+    public static Role toEntity(RoleListQueryRequest request) {
+        return DtoAssembler.toDto(request, Role.class);
+    }
+
+    public static Role toEntity(RoleCreateRequest request) {
+        return DtoAssembler.toDto(request, Role.class);
+    }
+
+    public static Role toEntity(RoleUpdateRequest request) {
+        return DtoAssembler.toDto(request, Role.class);
+    }
+
+    public static RoleResponse toResponse(Role role) {
+        return DtoAssembler.toDto(role, RoleResponse.class);
+    }
+
+    public static IPage<RoleResponse> toPageResponse(IPage<Role> page) {
+        return DtoAssembler.toPage(page, RoleAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/TeamAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/TeamAssembler.java
new file mode 100644
index 0000000..fbb33dc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/TeamAssembler.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.Team;
+import org.apache.streampark.console.system.request.team.TeamCreateRequest;
+import org.apache.streampark.console.system.request.team.TeamListQueryRequest;
+import org.apache.streampark.console.system.request.team.TeamUpdateRequest;
+import org.apache.streampark.console.system.response.team.TeamResponse;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/** Converts between team entities and API request/response contracts. */
+public final class TeamAssembler {
+
+    private TeamAssembler() {
+    }
+
+    public static Team toEntity(TeamListQueryRequest request) {
+        return DtoAssembler.toDto(request, Team.class);
+    }
+
+    public static Team toEntity(TeamCreateRequest request) {
+        return DtoAssembler.toDto(request, Team.class);
+    }
+
+    public static Team toEntity(TeamUpdateRequest request) {
+        return DtoAssembler.toDto(request, Team.class);
+    }
+
+    public static TeamResponse toResponse(Team team) {
+        return DtoAssembler.toDto(team, TeamResponse.class);
+    }
+
+    public static IPage<TeamResponse> toPageResponse(IPage<Team> page) {
+        return DtoAssembler.toPage(page, TeamAssembler::toResponse);
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/UserAssembler.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/UserAssembler.java
new file mode 100644
index 0000000..bc116dc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/assembler/UserAssembler.java
@@ -0,0 +1,144 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.assembler.DtoAssembler;
+import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.request.user.UserCreateRequest;
+import org.apache.streampark.console.system.request.user.UserListQueryRequest;
+import org.apache.streampark.console.system.request.user.UserPasswordUpdateRequest;
+import org.apache.streampark.console.system.request.user.UserUpdateRequest;
+import org.apache.streampark.console.system.response.user.UserBriefResponse;
+import org.apache.streampark.console.system.response.user.UserResponse;
+import org.apache.streampark.console.system.response.user.UserSessionResponse;
+import org.apache.streampark.console.system.response.user.UserUpdateResponse;
+import org.apache.streampark.console.system.service.result.UserLoginResult;
+import org.apache.streampark.console.system.service.result.UserUpdateResult;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Converts between user entities and API request/response contracts. */
+public final class UserAssembler {
+
+    private UserAssembler() {
+    }
+
+    public static User toEntity(UserListQueryRequest request) {
+        return DtoAssembler.toDto(request, User.class);
+    }
+
+    public static User toEntity(UserCreateRequest request) {
+        return DtoAssembler.toDto(request, User.class);
+    }
+
+    public static User toEntity(UserUpdateRequest request) {
+        return DtoAssembler.toDto(request, User.class);
+    }
+
+    public static User toEntity(UserPasswordUpdateRequest request) {
+        return DtoAssembler.toDto(request, User.class);
+    }
+
+    public static UserResponse toResponse(User user) {
+        if (user == null) {
+            return null;
+        }
+        UserResponse response = new UserResponse();
+        response.setUserId(user.getUserId());
+        response.setUsername(user.getUsername());
+        response.setEmail(user.getEmail());
+        response.setUserType(user.getUserType());
+        response.setLoginType(user.getLoginType());
+        response.setStatus(user.getStatus());
+        response.setCreateTime(user.getCreateTime());
+        response.setModifyTime(user.getModifyTime());
+        response.setLastLoginTime(user.getLastLoginTime());
+        response.setSex(user.getSex());
+        response.setDescription(user.getDescription());
+        response.setNickName(user.getNickName());
+        response.setLastTeamId(user.getLastTeamId());
+        response.setId(user.getId());
+        return response;
+    }
+
+    public static List<UserResponse> toResponseList(List<User> users) {
+        return DtoAssembler.toList(users, UserAssembler::toResponse);
+    }
+
+    public static IPage<UserResponse> toPageResponse(IPage<User> page) {
+        return DtoAssembler.toPage(page, UserAssembler::toResponse);
+    }
+
+    public static UserBriefResponse toBriefResponse(User user) {
+        if (user == null) {
+            return null;
+        }
+        UserBriefResponse response = new UserBriefResponse();
+        response.setUserId(user.getUserId());
+        response.setUsername(user.getUsername());
+        response.setNickName(user.getNickName());
+        response.setDescription(user.getDescription());
+        response.setLastTeamId(user.getLastTeamId());
+        response.setId(user.getId());
+        return response;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static UserSessionResponse toSessionResponse(Map<String, Object> userInfo) {
+        if (userInfo == null) {
+            return null;
+        }
+        UserSessionResponse response = new UserSessionResponse();
+        response.setToken((String) userInfo.get("token"));
+        response.setExpire((String) userInfo.get("expire"));
+        Object userObj = userInfo.get("user");
+        if (userObj instanceof User) {
+            response.setUser(toBriefResponse((User) userObj));
+        }
+        Object permissions = userInfo.get("permissions");
+        if (permissions instanceof Set) {
+            response.setPermissions((Set<String>) permissions);
+        }
+        return response;
+    }
+
+    public static UserUpdateResponse toUpdateResponse(UserUpdateResult result) {
+        UserUpdateResponse response = new UserUpdateResponse();
+        if (result != null) {
+            response.setNeedTransferResource(result.isNeedTransferResource());
+        }
+        return response;
+    }
+
+    public static RestResponseBody<UserSessionResponse> toLoginResponse(UserLoginResult result) {
+        if (result == null) {
+            return RestResponseBody.success(null);
+        }
+        if (result.getLoginCode() != null) {
+            return RestResponseBody.<UserSessionResponse>success(null)
+                .extra(RestResponse.CODE_KEY, result.getLoginCode());
+        }
+        return RestResponseBody.success(toSessionResponse(result.getUserInfo()));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/AccessTokenController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/AccessTokenController.java
index 604bbcc..2d90f41 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/AccessTokenController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/AccessTokenController.java
@@ -18,25 +18,34 @@
 package org.apache.streampark.console.system.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.enums.AccessTokenStateEnum;
 import org.apache.streampark.console.core.util.ServiceHelper;
+import org.apache.streampark.console.system.assembler.AccessTokenAssembler;
 import org.apache.streampark.console.system.entity.AccessToken;
 import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.request.token.TokenCreateRequest;
+import org.apache.streampark.console.system.request.token.TokenDeleteRequest;
+import org.apache.streampark.console.system.request.token.TokenListQueryRequest;
+import org.apache.streampark.console.system.request.token.TokenToggleRequest;
+import org.apache.streampark.console.system.response.token.AccessTokenResponse;
 import org.apache.streampark.console.system.service.AccessTokenService;
+import org.apache.streampark.console.system.service.result.AccessTokenCreateResult;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.Valid;
 
+@Validated
 @RestController
 @RequestMapping("token")
 public class AccessTokenController {
@@ -46,44 +55,53 @@
 
     @PostMapping(value = "create")
     @RequiresPermissions("token:add")
-    public RestResponse createToken(
-                                    @NotNull(message = "{required}") Long userId,
-                                    @RequestParam(required = false) String description) throws Exception {
-        return accessTokenService.create(userId, description);
+    public RestResponseBody<AccessToken> createToken(@Valid @FormOrJson TokenCreateRequest request) throws Exception {
+        AccessTokenCreateResult result =
+            accessTokenService.create(request.getUserId(), request.getDescription());
+        if (!result.isCreated()) {
+            return RestResponseBody.<AccessToken>success(null)
+                .extra("code", 0)
+                .message(result.getMessage());
+        }
+        return RestResponseBody.success(result.getAccessToken());
     }
 
     @PostMapping(value = "check")
-    public RestResponse verifyToken() {
+    public RestResponseBody<Integer> verifyToken() {
         Long userId = ServiceHelper.getUserId();
-        RestResponse restResponse = RestResponse.success();
         AccessToken accessToken = accessTokenService.getByUserId(userId);
         if (accessToken == null) {
-            restResponse.data(AccessTokenStateEnum.NULL.get());
-        } else if (AccessToken.STATUS_DISABLE.equals(accessToken.getStatus())) {
-            restResponse.data(AccessTokenStateEnum.INVALID_TOKEN.get());
-        } else if (User.STATUS_LOCK.equals(accessToken.getUserStatus())) {
-            restResponse.data(AccessTokenStateEnum.LOCKED_USER.get());
+            return RestResponseBody.success(AccessTokenStateEnum.NULL.get());
         }
-        return restResponse;
+        if (AccessToken.STATUS_DISABLE.equals(accessToken.getStatus())) {
+            return RestResponseBody.success(AccessTokenStateEnum.INVALID_TOKEN.get());
+        }
+        if (User.STATUS_LOCK.equals(accessToken.getUserStatus())) {
+            return RestResponseBody.success(AccessTokenStateEnum.LOCKED_USER.get());
+        }
+        return RestResponseBody.success(null);
     }
 
     @PostMapping(value = "list")
     @RequiresPermissions("token:view")
-    public RestResponse tokensList(RestRequest restRequest, AccessToken accessToken) {
-        IPage<AccessToken> accessTokens = accessTokenService.getPage(accessToken, restRequest);
-        return RestResponse.success(accessTokens);
+    public RestResponseBody<IPage<AccessTokenResponse>> tokensList(
+                                                                   RestRequest restRequest,
+                                                                   TokenListQueryRequest query) {
+        IPage<AccessToken> accessTokens =
+            accessTokenService.getPage(AccessTokenAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(AccessTokenAssembler.toPageResponse(accessTokens));
     }
 
     @PostMapping("toggle")
     @RequiresPermissions("token:add")
-    public RestResponse toggleToken(@NotNull(message = "{required}") Long tokenId) {
-        return accessTokenService.toggle(tokenId);
+    public RestResponseBody<Boolean> toggleToken(@Valid @FormOrJson TokenToggleRequest request) {
+        return RestResponseBody.success(accessTokenService.toggle(request.getTokenId()));
     }
 
     @DeleteMapping(value = "delete")
     @RequiresPermissions("token:delete")
-    public RestResponse deleteToken(@NotNull(message = "{required}") Long tokenId) {
-        boolean res = accessTokenService.removeById(tokenId);
-        return RestResponse.success(res);
+    public RestResponseBody<Boolean> deleteToken(@Valid @FormOrJson TokenDeleteRequest request) {
+        boolean res = accessTokenService.removeById(request.getTokenId());
+        return RestResponseBody.success(res);
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
index 337353e..9aaf147 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
@@ -18,11 +18,23 @@
 package org.apache.streampark.console.system.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
+import org.apache.streampark.console.system.assembler.MemberAssembler;
+import org.apache.streampark.console.system.assembler.TeamAssembler;
+import org.apache.streampark.console.system.assembler.UserAssembler;
 import org.apache.streampark.console.system.entity.Member;
-import org.apache.streampark.console.system.entity.Team;
-import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.request.member.MemberCandidateUsersRequest;
+import org.apache.streampark.console.system.request.member.MemberCheckUserRequest;
+import org.apache.streampark.console.system.request.member.MemberCreateRequest;
+import org.apache.streampark.console.system.request.member.MemberDeleteRequest;
+import org.apache.streampark.console.system.request.member.MemberListQueryRequest;
+import org.apache.streampark.console.system.request.member.MemberTeamsRequest;
+import org.apache.streampark.console.system.request.member.MemberUpdateRequest;
+import org.apache.streampark.console.system.response.member.MemberResponse;
+import org.apache.streampark.console.system.response.team.TeamResponse;
+import org.apache.streampark.console.system.response.user.UserResponse;
 import org.apache.streampark.console.system.service.MemberService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -38,9 +50,8 @@
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
 
-import java.util.List;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Validated
@@ -52,50 +63,52 @@
     private MemberService memberService;
 
     @PostMapping("list")
-    public RestResponse memberList(RestRequest restRequest, Member member) {
-        IPage<Member> userList = memberService.getPage(member, restRequest);
-        return RestResponse.success(userList);
+    public RestResponseBody<IPage<MemberResponse>> memberList(RestRequest restRequest, MemberListQueryRequest query) {
+        IPage<Member> userList = memberService.getPage(MemberAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(MemberAssembler.toPageResponse(userList));
     }
 
     @PostMapping("candidateUsers")
-    public RestResponse candidateUsers(Long teamId) {
-        List<User> userList = memberService.listUsersNotInTeam(teamId);
-        return RestResponse.success(userList);
+    public RestResponseBody<java.util.List<UserResponse>> candidateUsers(@Valid MemberCandidateUsersRequest request) {
+        return RestResponseBody.success(
+            UserAssembler.toResponseList(memberService.listUsersNotInTeam(request.getTeamId())));
     }
 
     @PostMapping("teams")
-    public RestResponse listTeams(Long userId) {
-        List<Team> teamList = memberService.listTeamsByUserId(userId);
-        return RestResponse.success(teamList);
+    public RestResponseBody<java.util.List<TeamResponse>> listTeams(@Valid MemberTeamsRequest request) {
+        return RestResponseBody.success(
+            memberService.listTeamsByUserId(request.getUserId()).stream()
+                .map(TeamAssembler::toResponse)
+                .collect(Collectors.toList()));
     }
 
     @PostMapping("check/user")
-    public RestResponse check(@NotNull(message = "{required}") Long teamId, String userName) {
-        Member result = this.memberService.getByTeamIdUserName(teamId, userName);
-        return RestResponse.success(result == null);
+    public RestResponseBody<Boolean> check(@Valid MemberCheckUserRequest request) {
+        Member result = this.memberService.getByTeamIdUserName(request.getTeamId(), request.getUserName());
+        return RestResponseBody.success(result == null);
     }
 
     @PostMapping("post")
-    @Permission(team = "#member.teamId")
+    @Permission(team = "#request.teamId")
     @RequiresPermissions("member:add")
-    public RestResponse create(@Valid Member member) {
-        this.memberService.createMember(member);
-        return RestResponse.success();
+    public RestResponseBody<Void> create(@Valid @FormOrJson MemberCreateRequest request) {
+        this.memberService.createMember(MemberAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("delete")
-    @Permission(team = "#member.teamId")
+    @Permission(team = "#request.teamId")
     @RequiresPermissions("member:delete")
-    public RestResponse delete(Member member) {
-        this.memberService.remove(member.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> delete(@Valid @FormOrJson MemberDeleteRequest request) {
+        this.memberService.remove(request.getId());
+        return RestResponseBody.success();
     }
 
     @PutMapping("update")
-    @Permission(team = "#member.teamId")
+    @Permission(team = "#request.teamId")
     @RequiresPermissions("member:update")
-    public RestResponse update(Member member) {
-        this.memberService.updateMember(member);
-        return RestResponse.success();
+    public RestResponseBody<Void> update(@Valid @FormOrJson MemberUpdateRequest request) {
+        this.memberService.updateMember(MemberAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MenuController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MenuController.java
index 7bfba2a..a87f1c6 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MenuController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MenuController.java
@@ -17,10 +17,14 @@
 
 package org.apache.streampark.console.system.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.domain.router.VueRouter;
 import org.apache.streampark.console.core.util.ServiceHelper;
+import org.apache.streampark.console.system.assembler.MenuAssembler;
 import org.apache.streampark.console.system.entity.Menu;
+import org.apache.streampark.console.system.request.menu.MenuListQueryRequest;
+import org.apache.streampark.console.system.request.menu.MenuRouterRequest;
+import org.apache.streampark.console.system.response.menu.MenuListResponse;
 import org.apache.streampark.console.system.service.MenuService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -33,7 +37,6 @@
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
-import java.util.Map;
 
 @Slf4j
 @Validated
@@ -45,16 +48,15 @@
     private MenuService menuService;
 
     @PostMapping("router")
-    public RestResponse getUserRouters(Long teamId) {
-        // TODO The teamId is required, get routers should be called after choose teamId.
-        List<VueRouter<Menu>> routers = this.menuService.listRouters(ServiceHelper.getUserId(), teamId);
-        return RestResponse.success(routers);
+    public RestResponseBody<List<VueRouter<Menu>>> getUserRouters(MenuRouterRequest request) {
+        List<VueRouter<Menu>> routers = this.menuService.listRouters(ServiceHelper.getUserId(), request.getTeamId());
+        return RestResponseBody.success(routers);
     }
 
     @PostMapping("list")
     @RequiresPermissions("menu:view")
-    public RestResponse menuList(Menu menu) {
-        Map<String, Object> menuMap = this.menuService.listMenuMap(menu);
-        return RestResponse.success(menuMap);
+    public RestResponseBody<MenuListResponse> menuList(MenuListQueryRequest query) {
+        return RestResponseBody.success(
+            MenuAssembler.toListResponse(this.menuService.listMenuMap(MenuAssembler.toEntity(query))));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/PassportController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/PassportController.java
index 732d9ed..65d35f9 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/PassportController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/PassportController.java
@@ -19,11 +19,17 @@
 
 import org.apache.streampark.common.util.DateUtils;
 import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.enums.AuthenticationType;
 import org.apache.streampark.console.core.enums.LoginTypeEnum;
+import org.apache.streampark.console.system.assembler.PassportAssembler;
+import org.apache.streampark.console.system.assembler.UserAssembler;
 import org.apache.streampark.console.system.authentication.JWTToken;
 import org.apache.streampark.console.system.authentication.JWTUtil;
 import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.request.passport.PassportSignInRequest;
+import org.apache.streampark.console.system.response.user.UserSessionResponse;
 import org.apache.streampark.console.system.security.Authenticator;
 import org.apache.streampark.console.system.service.UserService;
 
@@ -42,7 +48,6 @@
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 @Slf4j
 @Validated
@@ -63,7 +68,7 @@
     private Boolean ldapEnable;
 
     @PostMapping("signtype")
-    public RestResponse type() {
+    public RestResponseBody<List<String>> type() {
         List<String> types = new ArrayList<>();
         types.add(LoginTypeEnum.PASSWORD.name().toLowerCase());
         if (ssoEnable) {
@@ -72,45 +77,47 @@
         if (ldapEnable) {
             types.add(LoginTypeEnum.LDAP.name().toLowerCase());
         }
-        return RestResponse.success(types);
+        return RestResponseBody.success(types);
     }
 
     @PostMapping("signin")
-    public RestResponse signin(User loginUser) throws Exception {
+    public RestResponseBody<UserSessionResponse> signin(@FormOrJson PassportSignInRequest request) throws Exception {
 
-        if (StringUtils.isEmpty(loginUser.getUsername())) {
-            return RestResponse.success().put("code", 0);
+        if (StringUtils.isEmpty(request.getUsername())) {
+            return RestResponseBody.<UserSessionResponse>success(null).extra("code", 0);
         }
 
-        User user =
-            authenticator.authenticate(loginUser.getUsername(), loginUser.getPassword(), loginUser.getLoginType());
+        User user = authenticator.authenticate(
+            request.getUsername(), request.getPassword(), PassportAssembler.toLoginType(request));
 
         if (user == null) {
-            return RestResponse.success().put("code", 0);
+            return RestResponseBody.<UserSessionResponse>success(null).extra("code", 0);
         }
 
         if (User.STATUS_LOCK.equals(user.getStatus())) {
-            return RestResponse.success().put("code", 1);
+            return RestResponseBody.<UserSessionResponse>success(null).extra("code", 1);
         }
 
-        this.userService.updateLoginTime(loginUser.getUsername());
+        this.userService.updateLoginTime(request.getUsername());
         String token = JWTUtil.sign(user, AuthenticationType.SIGN);
 
         LocalDateTime expireTime = LocalDateTime.now().plusSeconds(JWTUtil.getTTLOfSecond());
         String ttl = DateUtils.formatFullTime(expireTime);
 
-        // generate UserInfo
         String userId = RandomStringUtils.randomAlphanumeric(20);
         user.setId(userId);
         JWTToken jwtToken = new JWTToken(token, ttl);
-        Map<String, Object> userInfo = userService.generateFrontendUserInfo(user, jwtToken);
 
-        return new RestResponse().data(userInfo);
+        UserSessionResponse session =
+            UserAssembler.toSessionResponse(userService.generateFrontendUserInfo(user, jwtToken));
+        return RestResponseBody.success(session);
     }
 
     @PostMapping("signout")
-    public RestResponse signout() {
+    public RestResponseBody<Void> signout() {
         SecurityUtils.getSubject().logout();
-        return new RestResponse();
+        RestResponseBody<Void> body = RestResponseBody.success();
+        body.setStatus(RestResponse.STATUS_SUCCESS);
+        return body;
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/RoleController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/RoleController.java
index 86f93c7..b292fde 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/RoleController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/RoleController.java
@@ -18,9 +18,18 @@
 package org.apache.streampark.console.system.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.system.assembler.RoleAssembler;
 import org.apache.streampark.console.system.entity.Role;
 import org.apache.streampark.console.system.entity.RoleMenu;
+import org.apache.streampark.console.system.request.role.RoleCheckNameRequest;
+import org.apache.streampark.console.system.request.role.RoleCreateRequest;
+import org.apache.streampark.console.system.request.role.RoleDeleteRequest;
+import org.apache.streampark.console.system.request.role.RoleListQueryRequest;
+import org.apache.streampark.console.system.request.role.RoleMenuQueryRequest;
+import org.apache.streampark.console.system.request.role.RoleUpdateRequest;
+import org.apache.streampark.console.system.response.role.RoleResponse;
 import org.apache.streampark.console.system.service.RoleMenuService;
 import org.apache.streampark.console.system.service.RoleService;
 
@@ -37,7 +46,6 @@
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
 
 import java.util.List;
 import java.util.stream.Collectors;
@@ -55,44 +63,44 @@
 
     @PostMapping("list")
     @RequiresPermissions("role:view")
-    public RestResponse roleList(RestRequest restRequest, Role role) {
-        IPage<Role> roleList = roleService.getPage(role, restRequest);
-        return RestResponse.success(roleList);
+    public RestResponseBody<IPage<RoleResponse>> roleList(RestRequest restRequest, RoleListQueryRequest query) {
+        IPage<Role> roleList = roleService.getPage(RoleAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(RoleAssembler.toPageResponse(roleList));
     }
 
     @PostMapping("check/name")
-    public RestResponse checkRoleName(@NotBlank(message = "{required}") String roleName) {
-        Role result = this.roleService.getByName(roleName);
-        return RestResponse.success(result == null);
+    public RestResponseBody<Boolean> checkRoleName(@Valid RoleCheckNameRequest request) {
+        Role result = this.roleService.getByName(request.getRoleName());
+        return RestResponseBody.success(result == null);
     }
 
     @PostMapping("menu")
-    public RestResponse getRoleMenus(@NotBlank(message = "{required}") String roleId) {
-        List<RoleMenu> roleMenuList = this.roleMenuService.listByRoleId(roleId);
+    public RestResponseBody<List<String>> getRoleMenus(@Valid RoleMenuQueryRequest request) {
+        List<RoleMenu> roleMenuList = this.roleMenuService.listByRoleId(request.getRoleId());
         List<String> menuIdList = roleMenuList.stream()
             .map(roleMenu -> String.valueOf(roleMenu.getMenuId()))
             .collect(Collectors.toList());
-        return RestResponse.success(menuIdList);
+        return RestResponseBody.success(menuIdList);
     }
 
     @PostMapping("post")
     @RequiresPermissions("role:add")
-    public RestResponse addRole(@Valid Role role) {
-        this.roleService.createRole(role);
-        return RestResponse.success();
+    public RestResponseBody<Void> addRole(@Valid @FormOrJson RoleCreateRequest request) {
+        this.roleService.createRole(RoleAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("delete")
     @RequiresPermissions("role:delete")
-    public RestResponse deleteRole(Long roleId) {
-        this.roleService.removeById(roleId);
-        return RestResponse.success();
+    public RestResponseBody<Void> deleteRole(@Valid @FormOrJson RoleDeleteRequest request) {
+        this.roleService.removeById(request.getRoleId());
+        return RestResponseBody.success();
     }
 
     @PutMapping("update")
     @RequiresPermissions("role:update")
-    public RestResponse updateRole(Role role) throws Exception {
-        this.roleService.updateRole(role);
-        return RestResponse.success();
+    public RestResponseBody<Void> updateRole(@Valid @FormOrJson RoleUpdateRequest request) {
+        this.roleService.updateRole(RoleAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/SsoController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/SsoController.java
index 4d9b501..919c6b6 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/SsoController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/SsoController.java
@@ -17,10 +17,12 @@
 
 package org.apache.streampark.console.system.controller;
 
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.core.enums.LoginTypeEnum;
+import org.apache.streampark.console.system.assembler.UserAssembler;
 import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.response.user.UserSessionResponse;
 import org.apache.streampark.console.system.security.Authenticator;
 import org.apache.streampark.console.system.service.UserService;
 
@@ -67,7 +69,7 @@
 
     @GetMapping("token")
     @ResponseBody
-    public RestResponse token() throws Exception {
+    public RestResponseBody<UserSessionResponse> token() throws Exception {
         // Check SSO enable status
         ApiAlertException.throwIfTrue(
             !ssoEnable,
@@ -91,6 +93,6 @@
 
         User user = authenticator.authenticate(principal.getName(), null, LoginTypeEnum.SSO);
 
-        return userService.getLoginUserInfo(user);
+        return UserAssembler.toLoginResponse(userService.getLoginUserInfo(user));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/TeamController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/TeamController.java
index 5a9c464..e51d6c2 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/TeamController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/TeamController.java
@@ -18,8 +18,16 @@
 package org.apache.streampark.console.system.controller;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.base.web.FormOrJson;
+import org.apache.streampark.console.system.assembler.TeamAssembler;
 import org.apache.streampark.console.system.entity.Team;
+import org.apache.streampark.console.system.request.team.TeamCheckNameRequest;
+import org.apache.streampark.console.system.request.team.TeamCreateRequest;
+import org.apache.streampark.console.system.request.team.TeamDeleteRequest;
+import org.apache.streampark.console.system.request.team.TeamListQueryRequest;
+import org.apache.streampark.console.system.request.team.TeamUpdateRequest;
+import org.apache.streampark.console.system.response.team.TeamResponse;
 import org.apache.streampark.console.system.service.TeamService;
 
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -35,7 +43,6 @@
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
 
 @Slf4j
 @Validated
@@ -47,35 +54,35 @@
     private TeamService teamService;
 
     @PostMapping("list")
-    public RestResponse teamList(RestRequest restRequest, Team team) {
-        IPage<Team> teamList = teamService.getPage(team, restRequest);
-        return RestResponse.success(teamList);
+    public RestResponseBody<IPage<TeamResponse>> teamList(RestRequest restRequest, TeamListQueryRequest query) {
+        IPage<Team> teamList = teamService.getPage(TeamAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(TeamAssembler.toPageResponse(teamList));
     }
 
     @PostMapping("check/name")
-    public RestResponse checkTeamName(@NotBlank(message = "{required}") String teamName) {
-        Team result = this.teamService.getByName(teamName);
-        return RestResponse.success(result == null);
+    public RestResponseBody<Boolean> checkTeamName(@Valid TeamCheckNameRequest request) {
+        Team result = this.teamService.getByName(request.getTeamName());
+        return RestResponseBody.success(result == null);
     }
 
     @PostMapping("post")
     @RequiresPermissions("team:add")
-    public RestResponse addTeam(@Valid Team team) {
-        this.teamService.createTeam(team);
-        return RestResponse.success();
+    public RestResponseBody<Void> addTeam(@Valid @FormOrJson TeamCreateRequest request) {
+        this.teamService.createTeam(TeamAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("delete")
     @RequiresPermissions("team:delete")
-    public RestResponse deleteTeam(Team team) {
-        this.teamService.removeById(team.getId());
-        return RestResponse.success();
+    public RestResponseBody<Void> deleteTeam(@Valid @FormOrJson TeamDeleteRequest request) {
+        this.teamService.removeById(request.getId());
+        return RestResponseBody.success();
     }
 
     @PutMapping("update")
     @RequiresPermissions("team:update")
-    public RestResponse updateTeam(Team team) {
-        this.teamService.updateTeam(team);
-        return RestResponse.success();
+    public RestResponseBody<Void> updateTeam(@Valid @FormOrJson TeamUpdateRequest request) {
+        this.teamService.updateTeam(TeamAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
index 262534d..88a7380 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
@@ -19,13 +19,27 @@
 
 import org.apache.streampark.console.base.domain.ResponseCode;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
 import org.apache.streampark.console.base.exception.ApiAlertException;
+import org.apache.streampark.console.base.web.FormOrJson;
 import org.apache.streampark.console.core.annotation.Permission;
 import org.apache.streampark.console.core.enums.LoginTypeEnum;
 import org.apache.streampark.console.core.util.ServiceHelper;
+import org.apache.streampark.console.system.assembler.UserAssembler;
 import org.apache.streampark.console.system.entity.Team;
 import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.request.user.UserCheckNameRequest;
+import org.apache.streampark.console.system.request.user.UserCreateRequest;
+import org.apache.streampark.console.system.request.user.UserDeleteRequest;
+import org.apache.streampark.console.system.request.user.UserListQueryRequest;
+import org.apache.streampark.console.system.request.user.UserPasswordUpdateRequest;
+import org.apache.streampark.console.system.request.user.UserResetPasswordRequest;
+import org.apache.streampark.console.system.request.user.UserTeamIdRequest;
+import org.apache.streampark.console.system.request.user.UserTransferResourceRequest;
+import org.apache.streampark.console.system.request.user.UserUpdateRequest;
+import org.apache.streampark.console.system.response.user.UserResponse;
+import org.apache.streampark.console.system.response.user.UserSessionResponse;
+import org.apache.streampark.console.system.response.user.UserUpdateResponse;
 import org.apache.streampark.console.system.service.TeamService;
 import org.apache.streampark.console.system.service.UserService;
 
@@ -43,10 +57,8 @@
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
 
 import java.util.List;
-import java.util.Map;
 
 @Slf4j
 @Validated
@@ -62,90 +74,90 @@
 
     @PostMapping("list")
     @RequiresPermissions(value = {"user:view", "app:view"}, logical = Logical.OR)
-    public RestResponse userList(RestRequest restRequest, User user) {
-        IPage<User> userList = userService.getPage(user, restRequest);
-        return RestResponse.success(userList);
+    public RestResponseBody<IPage<UserResponse>> userList(RestRequest restRequest, UserListQueryRequest query) {
+        IPage<User> userList = userService.getPage(UserAssembler.toEntity(query), restRequest);
+        return RestResponseBody.success(UserAssembler.toPageResponse(userList));
     }
 
     @PostMapping("post")
     @RequiresPermissions("user:add")
-    public RestResponse addUser(@Valid User user) throws Exception {
+    public RestResponseBody<Void> addUser(@Valid @FormOrJson UserCreateRequest request) throws Exception {
+        User user = UserAssembler.toEntity(request);
+        ApiAlertException.throwIfNull(user, "User create request cannot be null.");
         user.setLoginType(LoginTypeEnum.PASSWORD);
         this.userService.createUser(user);
-        return RestResponse.success();
+        return RestResponseBody.success();
     }
 
     @PutMapping("update")
-    @Permission(user = "#user.id")
+    @Permission(user = "#request.userId")
     @RequiresPermissions("user:update")
-    public RestResponse updateUser(@Valid User user) throws Exception {
-        return this.userService.updateUser(user);
+    public RestResponseBody<UserUpdateResponse> updateUser(@Valid @FormOrJson UserUpdateRequest request) throws Exception {
+        return RestResponseBody.success(
+            UserAssembler.toUpdateResponse(this.userService.updateUser(UserAssembler.toEntity(request))));
     }
 
     @PutMapping("transferResource")
     @RequiresPermissions("user:update")
-    public RestResponse transferResource(Long userId, Long targetUserId) {
-        this.userService.transferResource(userId, targetUserId);
-        return RestResponse.success();
+    public RestResponseBody<Void> transferResource(@Valid @FormOrJson UserTransferResourceRequest request) {
+        this.userService.transferResource(request.getUserId(), request.getTargetUserId());
+        return RestResponseBody.success();
     }
 
     @DeleteMapping("delete")
-    @Permission(user = "#userId")
+    @Permission(user = "#request.userId")
     @RequiresPermissions("user:delete")
-    public RestResponse deleteUser(Long userId) throws Exception {
-        this.userService.deleteUser(userId);
-        return RestResponse.success();
+    public RestResponseBody<Void> deleteUser(@Valid @FormOrJson UserDeleteRequest request) throws Exception {
+        this.userService.deleteUser(request.getUserId());
+        return RestResponseBody.success();
     }
 
     @PostMapping("getNoTokenUser")
-    public RestResponse getNoTokenUser() {
-        List<User> userList = this.userService.listNoTokenUser();
-        return RestResponse.success(userList);
+    public RestResponseBody<List<UserResponse>> getNoTokenUser() {
+        return RestResponseBody.success(UserAssembler.toResponseList(this.userService.listNoTokenUser()));
     }
 
     @PostMapping("check/name")
-    public RestResponse checkUserName(@NotBlank(message = "{required}") String username) {
-        boolean result = this.userService.getByUsername(username) == null;
-        return RestResponse.success(result);
+    public RestResponseBody<Boolean> checkUserName(@Valid UserCheckNameRequest request) {
+        boolean result = this.userService.getByUsername(request.getUsername()) == null;
+        return RestResponseBody.success(result);
     }
 
     @PutMapping("password")
-    @Permission(user = "#user.id")
-    public RestResponse updatePassword(User user) throws Exception {
-        userService.updatePassword(user);
-        return RestResponse.success();
+    @Permission(user = "#request.userId")
+    public RestResponseBody<Void> updatePassword(@Valid @FormOrJson UserPasswordUpdateRequest request) throws Exception {
+        userService.updatePassword(UserAssembler.toEntity(request));
+        return RestResponseBody.success();
     }
 
     @PutMapping("password/reset")
     @RequiresPermissions("user:reset")
-    public RestResponse resetPassword(@NotBlank(message = "{required}") String username) throws Exception {
-        String newPass = this.userService.resetPassword(username);
-        return RestResponse.success(newPass);
+    public RestResponseBody<String> resetPassword(@Valid @FormOrJson UserResetPasswordRequest request) throws Exception {
+        String newPass = this.userService.resetPassword(request.getUsername());
+        return RestResponseBody.success(newPass);
     }
 
     @PostMapping("set_team")
-    public RestResponse setTeam(Long teamId) {
-        Team team = teamService.getById(teamId);
+    public RestResponseBody<UserSessionResponse> setTeam(@Valid UserTeamIdRequest request) {
+        Team team = teamService.getById(request.getTeamId());
         if (team == null) {
-            return RestResponse.fail(ResponseCode.CODE_FAIL_ALERT, "TeamId is invalid, set team failed.");
+            return RestResponseBody.fail(ResponseCode.CODE_FAIL_ALERT, "TeamId is invalid, set team failed.");
         }
         User user = ServiceHelper.getLoginUser();
         ApiAlertException.throwIfNull(user, "Current login user is null, set team failed.");
-        // 1) set the latest team
-        userService.setLastTeam(teamId, user.getUserId());
+        userService.setLastTeam(request.getTeamId(), user.getUserId());
 
-        // 2) get latest userInfo
         user.dataMasking();
-        user.setLastTeamId(teamId);
+        user.setLastTeamId(request.getTeamId());
 
-        Map<String, Object> infoMap = userService.generateFrontendUserInfo(user, null);
-        return new RestResponse().data(infoMap);
+        return RestResponseBody.success(UserAssembler.toSessionResponse(
+            userService.generateFrontendUserInfo(user, null)));
     }
 
     @PostMapping("appOwners")
-    public RestResponse appOwners(Long teamId) {
-        List<User> userList = userService.listByTeamId(teamId);
+    public RestResponseBody<List<UserResponse>> appOwners(@Valid UserTeamIdRequest request) {
+        List<User> userList = userService.listByTeamId(request.getTeamId());
         userList.forEach(User::dataMasking);
-        return RestResponse.success(userList);
+        return RestResponseBody.success(UserAssembler.toResponseList(userList));
     }
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCandidateUsersRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCandidateUsersRequest.java
new file mode 100644
index 0000000..950123e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCandidateUsersRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /member/candidateUsers}. */
+@Getter
+@Setter
+public class MemberCandidateUsersRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCheckUserRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCheckUserRequest.java
new file mode 100644
index 0000000..44c518d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCheckUserRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /member/check/user}. */
+@Getter
+@Setter
+public class MemberCheckUserRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long teamId;
+
+    private String userName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCreateRequest.java
new file mode 100644
index 0000000..4625969
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberCreateRequest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /member/post}. */
+@Getter
+@Setter
+public class MemberCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long teamId;
+
+    @NotBlank
+    private String userName;
+
+    @NotNull
+    private Long roleId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberDeleteRequest.java
new file mode 100644
index 0000000..9e49bec
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberDeleteRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code DELETE /member/delete}. */
+@Getter
+@Setter
+public class MemberDeleteRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberListQueryRequest.java
new file mode 100644
index 0000000..81a5674
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberListQueryRequest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /member/list}. */
+@Getter
+@Setter
+public class MemberListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long teamId;
+
+    private String userName;
+
+    private String roleName;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberTeamsRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberTeamsRequest.java
new file mode 100644
index 0000000..9bba9ca
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberTeamsRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /member/teams}. */
+@Getter
+@Setter
+public class MemberTeamsRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long userId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberUpdateRequest.java
new file mode 100644
index 0000000..826de7d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/member/MemberUpdateRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.system.request.member;
+
+import org.apache.streampark.console.core.request.common.TeamScopedIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/** Request body for {@code PUT /member/update}. */
+@Getter
+@Setter
+public class MemberUpdateRequest extends TeamScopedIdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+
+    @NotNull
+    private Long roleId;
+
+    private String userName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuListQueryRequest.java
new file mode 100644
index 0000000..c3f0aae
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuListQueryRequest.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 org.apache.streampark.console.system.request.menu;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /menu/list}. */
+@Getter
+@Setter
+public class MenuListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String menuName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuRouterRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuRouterRequest.java
new file mode 100644
index 0000000..22a7489
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/menu/MenuRouterRequest.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 org.apache.streampark.console.system.request.menu;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /menu/router}. */
+@Getter
+@Setter
+public class MenuRouterRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long teamId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/passport/PassportSignInRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/passport/PassportSignInRequest.java
new file mode 100644
index 0000000..a71cccc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/passport/PassportSignInRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.system.request.passport;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /passport/signin}. */
+@Getter
+@Setter
+public class PassportSignInRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String username;
+
+    private String password;
+
+    /** Enum name such as {@code PASSWORD}, {@code LDAP}, or {@code SSO}. */
+    private String loginType;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCheckNameRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCheckNameRequest.java
new file mode 100644
index 0000000..3b8ffb7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCheckNameRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /role/check/name}. */
+@Getter
+@Setter
+public class RoleCheckNameRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String roleName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCreateRequest.java
new file mode 100644
index 0000000..734a90e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleCreateRequest.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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /role/post}. */
+@Getter
+@Setter
+public class RoleCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    @Size(max = 10, message = "{noMoreThan}")
+    private String roleName;
+
+    @Size(max = 255, message = "{noMoreThan}")
+    private String description;
+
+    /** Comma-separated menu ids, aligned with webapp {@code RoleParam.menuId}. */
+    private String menuId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleDeleteRequest.java
new file mode 100644
index 0000000..9442b9f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleDeleteRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code DELETE /role/delete}. */
+@Getter
+@Setter
+public class RoleDeleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long roleId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleListQueryRequest.java
new file mode 100644
index 0000000..47e8007
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleListQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /role/list}. */
+@Getter
+@Setter
+public class RoleListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String roleName;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleMenuQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleMenuQueryRequest.java
new file mode 100644
index 0000000..fbb06d6
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleMenuQueryRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /role/menu}. */
+@Getter
+@Setter
+public class RoleMenuQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String roleId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleUpdateRequest.java
new file mode 100644
index 0000000..f3f6852
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/role/RoleUpdateRequest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.streampark.console.system.request.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import java.io.Serializable;
+
+/** Request body for {@code PUT /role/update}. */
+@Getter
+@Setter
+public class RoleUpdateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long roleId;
+
+    @Size(max = 10, message = "{noMoreThan}")
+    private String roleName;
+
+    @Size(max = 255, message = "{noMoreThan}")
+    private String description;
+
+    /** Comma-separated menu ids. */
+    private String menuId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCheckNameRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCheckNameRequest.java
new file mode 100644
index 0000000..feadb9f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCheckNameRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.team;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /team/check/name}. */
+@Getter
+@Setter
+public class TeamCheckNameRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String teamName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCreateRequest.java
new file mode 100644
index 0000000..58c8ae1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamCreateRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.system.request.team;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /team/post}. */
+@Getter
+@Setter
+public class TeamCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    @Size(min = 4, max = 20, message = "{range}")
+    private String teamName;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamDeleteRequest.java
new file mode 100644
index 0000000..f636575
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamDeleteRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.system.request.team;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code DELETE /team/delete}. */
+@Getter
+@Setter
+public class TeamDeleteRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamListQueryRequest.java
new file mode 100644
index 0000000..cf68abe
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamListQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.system.request.team;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /team/list}. */
+@Getter
+@Setter
+public class TeamListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String teamName;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamUpdateRequest.java
new file mode 100644
index 0000000..b8b9088
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/team/TeamUpdateRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.streampark.console.system.request.team;
+
+import org.apache.streampark.console.core.request.common.IdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/** Request body for {@code PUT /team/update}. */
+@Getter
+@Setter
+public class TeamUpdateRequest extends IdRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    @Size(min = 4, max = 20, message = "{range}")
+    private String teamName;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenCreateRequest.java
new file mode 100644
index 0000000..f84fc9b
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenCreateRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.streampark.console.system.request.token;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /token/create}. */
+@Getter
+@Setter
+public class TokenCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long userId;
+
+    private String description;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenDeleteRequest.java
new file mode 100644
index 0000000..180e4e4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenDeleteRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.token;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code DELETE /token/delete}. */
+@Getter
+@Setter
+public class TokenDeleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long tokenId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenListQueryRequest.java
new file mode 100644
index 0000000..2c6287d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenListQueryRequest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.streampark.console.system.request.token;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /token/list}. */
+@Getter
+@Setter
+public class TokenListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+
+    private String username;
+
+    private Integer status;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenToggleRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenToggleRequest.java
new file mode 100644
index 0000000..b37d166
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/token/TokenToggleRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.token;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /token/toggle}. */
+@Getter
+@Setter
+public class TokenToggleRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long tokenId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCheckNameRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCheckNameRequest.java
new file mode 100644
index 0000000..c83b5e0
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCheckNameRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /user/check/name}. */
+@Getter
+@Setter
+public class UserCheckNameRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String username;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCreateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCreateRequest.java
new file mode 100644
index 0000000..f8dd70c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserCreateRequest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import org.apache.streampark.console.core.enums.UserTypeEnum;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+import java.io.Serializable;
+
+/** Request body for {@code POST /user/post}. */
+@Getter
+@Setter
+public class UserCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @Size(min = 4, max = 20, message = "{range}")
+    private String username;
+
+    private String password;
+
+    @Size(max = 50, message = "{noMoreThan}")
+    @Email(message = "{email}")
+    private String email;
+
+    private UserTypeEnum userType;
+
+    @NotBlank(message = "{required}")
+    private String status;
+
+    @NotBlank(message = "{required}")
+    private String sex;
+
+    @Size(max = 100, message = "{noMoreThan}")
+    private String description;
+
+    private String nickName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserDeleteRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserDeleteRequest.java
new file mode 100644
index 0000000..69b06ae
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserDeleteRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code DELETE /user/delete}. */
+@Getter
+@Setter
+public class UserDeleteRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long userId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserListQueryRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserListQueryRequest.java
new file mode 100644
index 0000000..db3a673
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserListQueryRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Query filters for {@code POST /user/list}. */
+@Getter
+@Setter
+public class UserListQueryRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String username;
+
+    private String status;
+
+    private String createTimeFrom;
+
+    private String createTimeTo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserPasswordUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserPasswordUpdateRequest.java
new file mode 100644
index 0000000..258df15
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserPasswordUpdateRequest.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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code PUT /user/password}. */
+@Getter
+@Setter
+public class UserPasswordUpdateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long userId;
+
+    private String oldPassword;
+
+    @NotBlank
+    private String password;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserResetPasswordRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserResetPasswordRequest.java
new file mode 100644
index 0000000..b11f234
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserResetPasswordRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+import java.io.Serializable;
+
+/** Request body for {@code PUT /user/password/reset}. */
+@Getter
+@Setter
+public class UserResetPasswordRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "{required}")
+    private String username;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTeamIdRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTeamIdRequest.java
new file mode 100644
index 0000000..c61dbdf
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTeamIdRequest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import org.apache.streampark.console.core.request.common.TeamIdRequest;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Request body for {@code POST /user/set_team} and {@code POST /user/appOwners}. */
+@Getter
+@Setter
+public class UserTeamIdRequest extends TeamIdRequest {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTransferResourceRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTransferResourceRequest.java
new file mode 100644
index 0000000..5f8ae07
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserTransferResourceRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+
+/** Request body for {@code PUT /user/transferResource}. */
+@Getter
+@Setter
+public class UserTransferResourceRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long userId;
+
+    @NotNull
+    private Long targetUserId;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserUpdateRequest.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserUpdateRequest.java
new file mode 100644
index 0000000..7e1f00c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/request/user/UserUpdateRequest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.system.request.user;
+
+import org.apache.streampark.console.core.enums.UserTypeEnum;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import java.io.Serializable;
+
+/** Request body for {@code PUT /user/update}. */
+@Getter
+@Setter
+public class UserUpdateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "{required}")
+    private Long userId;
+
+    @Size(max = 50, message = "{noMoreThan}")
+    @Email(message = "{email}")
+    private String email;
+
+    private UserTypeEnum userType;
+
+    private String status;
+
+    private String sex;
+
+    private String nickName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/member/MemberResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/member/MemberResponse.java
new file mode 100644
index 0000000..5972989
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/member/MemberResponse.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.streampark.console.system.response.member;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a team member record, aligned with webapp {@code MemberListRecord}.
+ */
+@Getter
+@Setter
+public class MemberResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long teamId;
+
+    private Long userId;
+
+    private Long roleId;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private String userName;
+
+    private String roleName;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/menu/MenuListResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/menu/MenuListResponse.java
new file mode 100644
index 0000000..18144a3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/menu/MenuListResponse.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.streampark.console.system.response.menu;
+
+import org.apache.streampark.console.base.domain.router.RouterTree;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/** Response for {@code POST /menu/list}. */
+@Getter
+@Setter
+@SuppressWarnings("java:S1948")
+public class MenuListResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<String> ids;
+
+    private Integer total;
+
+    private RouterTree<?> rows;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/role/RoleResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/role/RoleResponse.java
new file mode 100644
index 0000000..ff2b442
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/role/RoleResponse.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 org.apache.streampark.console.system.response.role;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a role record, aligned with webapp {@code RoleListRecord}.
+ */
+@Getter
+@Setter
+public class RoleResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long roleId;
+
+    private String roleName;
+
+    private String description;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/team/TeamResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/team/TeamResponse.java
new file mode 100644
index 0000000..aa86e9a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/team/TeamResponse.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 org.apache.streampark.console.system.response.team;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a team record, aligned with webapp {@code TeamListRecord}.
+ */
+@Getter
+@Setter
+public class TeamResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String teamName;
+
+    private String description;
+
+    private Date createTime;
+
+    private Date modifyTime;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/token/AccessTokenResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/token/AccessTokenResponse.java
new file mode 100644
index 0000000..bf4489a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/token/AccessTokenResponse.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.streampark.console.system.response.token;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for an access token record, aligned with webapp {@code TokenListRecord}.
+ */
+@Getter
+@Setter
+public class AccessTokenResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private Long userId;
+
+    private String token;
+
+    private Integer status;
+
+    private String description;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private String username;
+
+    private String userStatus;
+
+    private Integer finalStatus;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserBriefResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserBriefResponse.java
new file mode 100644
index 0000000..0bc3684
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserBriefResponse.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 org.apache.streampark.console.system.response.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Brief user profile returned after login or team switch, aligned with webapp {@code GetUserInfoModel}.
+ */
+@Getter
+@Setter
+public class UserBriefResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+
+    private String username;
+
+    private String nickName;
+
+    private String description;
+
+    private Long lastTeamId;
+
+    private String id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserResponse.java
new file mode 100644
index 0000000..c980a30
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserResponse.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.streampark.console.system.response.user;
+
+import org.apache.streampark.console.core.enums.LoginTypeEnum;
+import org.apache.streampark.console.core.enums.UserTypeEnum;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * API response for a user record, aligned with webapp {@code UserListRecord}.
+ */
+@Getter
+@Setter
+public class UserResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+
+    private String username;
+
+    private String email;
+
+    private UserTypeEnum userType;
+
+    private LoginTypeEnum loginType;
+
+    private String status;
+
+    private Date createTime;
+
+    private Date modifyTime;
+
+    private Date lastLoginTime;
+
+    private String sex;
+
+    private String description;
+
+    private String nickName;
+
+    private Long lastTeamId;
+
+    private String id;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserSessionResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserSessionResponse.java
new file mode 100644
index 0000000..bd8f1d4
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserSessionResponse.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.streampark.console.system.response.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * Session payload after login or team switch, aligned with webapp {@code LoginResultModel} /
+ * {@code TeamSetResponse}.
+ */
+@Getter
+@Setter
+public class UserSessionResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String token;
+
+    private String expire;
+
+    private UserBriefResponse user;
+
+    private Set<String> permissions;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserUpdateResponse.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserUpdateResponse.java
new file mode 100644
index 0000000..18b6c49
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/response/user/UserUpdateResponse.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 org.apache.streampark.console.system.response.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/** Result of a user update when resource transfer may be required. */
+@Getter
+@Setter
+public class UserUpdateResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Boolean needTransferResource;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/AccessTokenService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/AccessTokenService.java
index 61e9aa5..d126b54 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/AccessTokenService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/AccessTokenService.java
@@ -18,9 +18,9 @@
 package org.apache.streampark.console.system.service;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.InternalException;
 import org.apache.streampark.console.system.entity.AccessToken;
+import org.apache.streampark.console.system.service.result.AccessTokenCreateResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
@@ -33,10 +33,10 @@
      *
      * @param userId User id
      * @param description more description
-     * @return RestResponse
+     * @return create result with token entity or legacy failure metadata
      * @throws InternalException
      */
-    RestResponse create(Long userId, String description) throws Exception;
+    AccessTokenCreateResult create(Long userId, String description) throws Exception;
 
     /**
      * Retrieves a page of {@link AccessToken} objects based on the provided parameters.
@@ -51,9 +51,9 @@
      * Update information in token
      *
      * @param tokenId AccessToken id
-     * @return RestResponse
+     * @return whether the toggle is successful
      */
-    RestResponse toggle(Long tokenId);
+    boolean toggle(Long tokenId);
 
     /**
      * Get the corresponding AccessToken based on the user ID
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
index 9c907f7..71b517b 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
@@ -18,9 +18,10 @@
 package org.apache.streampark.console.system.service;
 
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.system.authentication.JWTToken;
 import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.service.result.UserLoginResult;
+import org.apache.streampark.console.system.service.result.UserUpdateResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
@@ -70,7 +71,7 @@
      * @param user user
      * @return
      */
-    RestResponse updateUser(User user) throws Exception;
+    UserUpdateResult updateUser(User user) throws Exception;
 
     /**
      * update password
@@ -155,9 +156,9 @@
      * Get login user information
      *
      * @param user User
-     * @return RestResponse
+     * @return login session result with optional loginCode for legacy wire format
      */
-    RestResponse getLoginUserInfo(User user) throws Exception;
+    UserLoginResult getLoginUserInfo(User user) throws Exception;
 
     void deleteUser(Long userId);
 }
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/AccessTokenServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/AccessTokenServiceImpl.java
index b18a069..9376363 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/AccessTokenServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/AccessTokenServiceImpl.java
@@ -17,9 +17,8 @@
 
 package org.apache.streampark.console.system.service.impl;
 
-import org.apache.streampark.console.base.domain.ResponseCode;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.mybatis.pager.MybatisPager;
 import org.apache.streampark.console.core.enums.AuthenticationType;
 import org.apache.streampark.console.system.authentication.JWTUtil;
@@ -28,6 +27,7 @@
 import org.apache.streampark.console.system.mapper.AccessTokenMapper;
 import org.apache.streampark.console.system.service.AccessTokenService;
 import org.apache.streampark.console.system.service.UserService;
+import org.apache.streampark.console.system.service.result.AccessTokenCreateResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -51,16 +51,20 @@
     private UserService userService;
 
     @Override
-    public RestResponse create(Long userId, String description) throws Exception {
+    public AccessTokenCreateResult create(Long userId, String description) throws Exception {
+        AccessTokenCreateResult result = new AccessTokenCreateResult();
         User user = userService.getById(userId);
         if (user == null) {
-            return RestResponse.success().put("code", 0).message("user not available");
+            result.setCreated(false);
+            result.setMessage("user not available");
+            return result;
         }
 
         AccessToken existAccessToken = baseMapper.selectByUserId(user.getUserId());
         if (existAccessToken != null) {
-            return RestResponse.success().put("code", 0)
-                .message(String.format("user %s already has a token", user.getUsername()));
+            result.setCreated(false);
+            result.setMessage(String.format("user %s already has a token", user.getUsername()));
+            return result;
         }
 
         String token = JWTUtil.sign(user, AuthenticationType.OPENAPI, Long.MAX_VALUE);
@@ -68,11 +72,12 @@
         accessToken.setToken(token);
         accessToken.setUserId(user.getUserId());
         accessToken.setDescription(description);
-
         accessToken.setStatus(AccessToken.STATUS_ENABLE);
 
         this.save(accessToken);
-        return RestResponse.success().data(accessToken);
+        result.setCreated(true);
+        result.setAccessToken(accessToken);
+        return result;
     }
 
     @Override
@@ -85,17 +90,12 @@
     }
 
     @Override
-    public RestResponse toggle(Long tokenId) {
+    public boolean toggle(Long tokenId) {
         AccessToken tokenInfo = baseMapper.selectById(tokenId);
-        if (tokenInfo == null) {
-            return RestResponse.fail(ResponseCode.CODE_FAIL_ALERT, "accessToken could not be found!");
-        }
-
-        if (User.STATUS_LOCK.equals(tokenInfo.getUserStatus())) {
-            return RestResponse.fail(
-                ResponseCode.CODE_FAIL_ALERT,
-                "user status is locked, could not operate this accessToken!");
-        }
+        ApiAlertException.throwIfNull(tokenInfo, "accessToken could not be found!");
+        ApiAlertException.throwIfTrue(
+            User.STATUS_LOCK.equals(tokenInfo.getUserStatus()),
+            "user status is locked, could not operate this accessToken!");
 
         Integer status = tokenInfo.getStatus().equals(AccessToken.STATUS_ENABLE)
             ? AccessToken.STATUS_DISABLE
@@ -104,7 +104,7 @@
         AccessToken updateObj = new AccessToken();
         updateObj.setStatus(status);
         updateObj.setId(tokenId);
-        return RestResponse.success(this.updateById(updateObj));
+        return this.updateById(updateObj);
     }
 
     @Override
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
index 383dfba..6012950 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
@@ -20,7 +20,6 @@
 import org.apache.streampark.common.util.AssertUtils;
 import org.apache.streampark.common.util.DateUtils;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.mybatis.pager.MybatisPager;
 import org.apache.streampark.console.base.util.ShaHashUtils;
@@ -41,6 +40,8 @@
 import org.apache.streampark.console.system.service.RoleService;
 import org.apache.streampark.console.system.service.TeamService;
 import org.apache.streampark.console.system.service.UserService;
+import org.apache.streampark.console.system.service.result.UserLoginResult;
+import org.apache.streampark.console.system.service.result.UserUpdateResult;
 
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -134,15 +135,17 @@
     }
 
     @Override
-    public RestResponse updateUser(User user) {
+    public UserUpdateResult updateUser(User user) {
         User existsUser = getById(user.getUserId());
         user.setLoginType(null);
         user.setPassword(null);
+        UserUpdateResult result = new UserUpdateResult();
         if (needTransferResource(existsUser, user)) {
-            return RestResponse.success(Collections.singletonMap("needTransferResource", true));
+            result.setNeedTransferResource(true);
+            return result;
         }
         updateById(user);
-        return RestResponse.success();
+        return result;
     }
 
     private boolean needTransferResource(User existsUser, User user) {
@@ -241,13 +244,16 @@
     }
 
     @Override
-    public RestResponse getLoginUserInfo(User user) throws Exception {
+    public UserLoginResult getLoginUserInfo(User user) throws Exception {
+        UserLoginResult result = new UserLoginResult();
         if (user == null) {
-            return RestResponse.success().put(RestResponse.CODE_KEY, 0);
+            result.setLoginCode(0);
+            return result;
         }
 
         if (User.STATUS_LOCK.equals(user.getStatus())) {
-            return RestResponse.success().put(RestResponse.CODE_KEY, 1);
+            result.setLoginCode(1);
+            return result;
         }
 
         this.updateLoginTime(user.getUsername());
@@ -256,13 +262,11 @@
         LocalDateTime expireTime = LocalDateTime.now().plusSeconds(JWTUtil.getTTLOfSecond());
         String ttl = DateUtils.formatFullTime(expireTime);
 
-        // generate UserInfo
         String userId = RandomStringUtils.randomAlphanumeric(20);
         user.setId(userId);
         JWTToken jwtToken = new JWTToken(token, ttl);
-        Map<String, Object> userInfo = generateFrontendUserInfo(user, jwtToken);
-
-        return RestResponse.success(userInfo);
+        result.setUserInfo(generateFrontendUserInfo(user, jwtToken));
+        return result;
     }
 
     @Override
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/AccessTokenCreateResult.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/AccessTokenCreateResult.java
new file mode 100644
index 0000000..f1e8fe1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/AccessTokenCreateResult.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.streampark.console.system.service.result;
+
+import org.apache.streampark.console.system.entity.AccessToken;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Service-layer result for access-token creation. */
+@Getter
+@Setter
+public class AccessTokenCreateResult {
+
+    private AccessToken accessToken;
+
+    private boolean created;
+
+    private String message;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserLoginResult.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserLoginResult.java
new file mode 100644
index 0000000..4417aab
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserLoginResult.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.streampark.console.system.service.result;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+/** Service-layer result for login session materialization. */
+@Getter
+@Setter
+public class UserLoginResult {
+
+    /** {@code null} on success; {@code 0} user missing; {@code 1} user locked. */
+    private Integer loginCode;
+
+    private Map<String, Object> userInfo;
+}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserUpdateResult.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserUpdateResult.java
new file mode 100644
index 0000000..b1582ae
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/result/UserUpdateResult.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 org.apache.streampark.console.system.service.result;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** Service-layer result for user update (resource transfer gate). */
+@Getter
+@Setter
+public class UserUpdateResult {
+
+    private boolean needTransferResource;
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/domain/RestResponseBodyTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/domain/RestResponseBodyTest.java
new file mode 100644
index 0000000..1a40f5c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/domain/RestResponseBodyTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.streampark.console.base.domain;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RestResponseBodyTest {
+
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    @Test
+    void shouldRoundTripTypedData() {
+        RestResponse response = RestResponse.success("payload");
+        RestResponseBody<String> body = RestResponseBody.from(response);
+
+        Assertions.assertEquals(RestResponse.STATUS_SUCCESS, body.getStatus());
+        Assertions.assertEquals("payload", body.getData());
+
+        RestResponse restored = body.toRestResponse();
+        Assertions.assertEquals("payload", restored.getDataAs(String.class));
+    }
+
+    @Test
+    void shouldSerializeExtensionFieldsAtTopLevel() throws Exception {
+        RestResponseBody<Boolean> body = RestResponseBody.success(false)
+            .message("syntax error")
+            .extra("type", 4)
+            .extra("start", 1)
+            .extra("end", 2);
+
+        String json = objectMapper.writeValueAsString(body);
+        Assertions.assertTrue(json.contains("\"type\":4"));
+        Assertions.assertTrue(json.contains("\"start\":1"));
+        Assertions.assertTrue(json.contains("\"end\":2"));
+    }
+
+    @Test
+    void shouldCopyLegacyExtraFieldsFromRestResponse() {
+        RestResponse response = RestResponse.success(false)
+            .message("err")
+            .put("type", 4)
+            .put("start", 1)
+            .put("end", 2);
+        RestResponseBody<Boolean> body = RestResponseBody.from(response);
+        Assertions.assertEquals(4, body.getExtensions().get("type"));
+        Assertions.assertEquals(1, body.getExtensions().get("start"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/handler/GlobalExceptionHandlerValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/handler/GlobalExceptionHandlerValidationTest.java
new file mode 100644
index 0000000..e37a0da
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/handler/GlobalExceptionHandlerValidationTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.streampark.console.base.handler;
+
+import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.validation.BeanPropertyBindingResult;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+
+class GlobalExceptionHandlerValidationTest {
+
+    private final GlobalExceptionHandler handler = new GlobalExceptionHandler();
+
+    @Test
+    void shouldHandleBindException() {
+        AlertConfigRequest target = new AlertConfigRequest();
+        BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(target, "request");
+        bindingResult.addError(new FieldError("request", "alertName", "must not be blank"));
+        BindException exception = new BindException(bindingResult);
+
+        RestResponseBody<Void> response = handler.validExceptionHandler(exception);
+
+        Assertions.assertEquals(RestResponse.STATUS_FAIL, response.getStatus());
+        Assertions.assertTrue(response.getMessage().contains("alertName"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolverTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolverTest.java
new file mode 100644
index 0000000..48c27a1
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/base/web/FormOrJsonArgumentResolverTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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 org.apache.streampark.console.base.web;
+
+import org.apache.streampark.console.system.request.team.TeamCreateRequest;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.ServletWebRequest;
+
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class FormOrJsonArgumentResolverTest {
+
+    private FormOrJsonArgumentResolver resolver;
+
+    @BeforeEach
+    void setUp() {
+        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+        resolver = new FormOrJsonArgumentResolver(new ObjectMapper(), validator);
+    }
+
+    @Test
+    void shouldBindFromJsonBody() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.setContentType("application/json");
+        request.setContent("{\"teamName\":\"demo\",\"description\":\"test\"}".getBytes());
+
+        org.springframework.core.MethodParameter parameter =
+            new org.springframework.core.MethodParameter(FormOrJsonArgumentResolverTest.class.getDeclaredMethod(
+                "sample", TeamCreateRequest.class), 0);
+
+        Object target = resolver.resolveArgument(
+            parameter, null, new ServletWebRequest(request), null);
+        TeamCreateRequest dto = (TeamCreateRequest) target;
+        assertEquals("demo", dto.getTeamName());
+    }
+
+    @Test
+    void shouldBindFromFormFields() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.setContentType("application/x-www-form-urlencoded");
+        request.addParameter("teamName", "demo");
+        request.addParameter("description", "test");
+
+        org.springframework.core.MethodParameter parameter =
+            new org.springframework.core.MethodParameter(FormOrJsonArgumentResolverTest.class.getDeclaredMethod(
+                "sample", TeamCreateRequest.class), 0);
+
+        Object target = resolver.resolveArgument(
+            parameter, null, new ServletWebRequest(request), null);
+        TeamCreateRequest dto = (TeamCreateRequest) target;
+        assertEquals("demo", dto.getTeamName());
+    }
+
+    @SuppressWarnings({"java:S1144", "java:S1172"})
+    private void sample(@FormOrJson TeamCreateRequest request) {
+        // referenced reflectively by resolveArgument tests
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/OpenAPIAspectTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/OpenAPIAspectTest.java
new file mode 100644
index 0000000..bb0419c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/OpenAPIAspectTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.apache.streampark.console.core.aspect;
+
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.controller.OpenAPIController;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.ThreadContext;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.junit.jupiter.api.AfterEach;
+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 org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class OpenAPIAspectTest {
+
+    private final OpenAPIAspect openAPIAspect = new OpenAPIAspect();
+
+    @BeforeEach
+    void bindSubject() {
+        Subject subject = new Subject.Builder(new DefaultSecurityManager()).buildSubject();
+        ThreadContext.bind(subject);
+    }
+
+    @AfterEach
+    void unbindSubject() {
+        ThreadContext.unbindSubject();
+        RequestContextHolder.resetRequestAttributes();
+    }
+
+    @Test
+    void shouldReturnRestResponseBodyWhenApiTokenNotUsed() throws Throwable {
+        RestResponseBody<Boolean> expected = RestResponseBody.success(true);
+        ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
+        MethodSignature signature = mock(MethodSignature.class);
+        when(joinPoint.getSignature()).thenReturn(signature);
+        when(signature.getName()).thenReturn("flinkStart");
+        when(joinPoint.proceed()).thenReturn(expected);
+
+        Object result = openAPIAspect.openAPI(joinPoint);
+        assertSame(expected, result);
+    }
+
+    @Test
+    void shouldBindOpenApiAliasFieldWhenApiTokenPresent() throws Throwable {
+        FlinkAppStartRequest request = new FlinkAppStartRequest();
+        RestResponseBody<Boolean> expected = RestResponseBody.success(true);
+        ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
+        MethodSignature signature = mock(MethodSignature.class);
+        Method method = OpenAPIController.class.getMethod("flinkStart", FlinkAppStartRequest.class);
+        when(joinPoint.getSignature()).thenReturn(signature);
+        when(signature.getMethod()).thenReturn(method);
+        when(joinPoint.getArgs()).thenReturn(new Object[]{request});
+        when(joinPoint.proceed()).thenReturn(expected);
+
+        Subject subject = ThreadContext.getSubject();
+        subject.getSession().setAttribute(org.apache.streampark.console.system.entity.AccessToken.IS_API_TOKEN, true);
+
+        MockHttpServletRequest httpRequest = new MockHttpServletRequest();
+        httpRequest.setParameter("restoreFromSavepoint", "true");
+        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpRequest));
+
+        Object result = openAPIAspect.openAPI(joinPoint);
+        assertSame(expected, result);
+        assertTrue(request.getRestoreOrTriggerSavepoint());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/PermissionAspectTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/PermissionAspectTest.java
new file mode 100644
index 0000000..04a4ad7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/aspect/PermissionAspectTest.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 org.apache.streampark.console.core.aspect;
+
+import org.apache.streampark.console.base.domain.RestResponseBody;
+import org.apache.streampark.console.core.controller.FlinkApplicationController;
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Method;
+
+/** Verifies {@link PermissionAspect} signature accepts {@link RestResponseBody} returns. */
+class PermissionAspectTest {
+
+    @Test
+    void permissionAspectShouldDeclareObjectReturnType() throws NoSuchMethodException {
+        Method aspectMethod = PermissionAspect.class.getDeclaredMethod(
+            "permissionAction", org.aspectj.lang.ProceedingJoinPoint.class);
+        Assertions.assertEquals(Object.class, aspectMethod.getReturnType());
+    }
+
+    @Test
+    void permissionProtectedControllerShouldReturnRestResponseBody() throws NoSuchMethodException {
+        Method getMethod = FlinkApplicationController.class.getMethod("get", FlinkAppIdRequest.class);
+        Assertions.assertTrue(
+            RestResponseBody.class.isAssignableFrom(getMethod.getReturnType()));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/DtoAssemblerTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/DtoAssemblerTest.java
new file mode 100644
index 0000000..79c82b7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/DtoAssemblerTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.request.flink.FlinkAppCreateRequest;
+import org.apache.streampark.console.core.response.flink.FlinkAppResponse;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DtoAssemblerTest {
+
+    @Test
+    void shouldCopyPropertiesBetweenCompatibleTypes() {
+        FlinkApplication app = new FlinkApplication();
+        app.setId(1L);
+        app.setJobName("demo");
+
+        FlinkAppResponse response = DtoAssembler.toDto(app, FlinkAppResponse.class);
+
+        Assertions.assertEquals(1L, response.getId());
+        Assertions.assertEquals("demo", response.getJobName());
+    }
+
+    @Test
+    void shouldMapPageRecords() {
+        FlinkApplication app = new FlinkApplication();
+        app.setId(2L);
+
+        Page<FlinkApplication> page = new Page<>(1, 10, 1);
+        page.setRecords(java.util.Collections.singletonList(app));
+
+        var responsePage = DtoAssembler.toPage(page, a -> DtoAssembler.toDto(a, FlinkAppResponse.class));
+
+        Assertions.assertEquals(1, responsePage.getRecords().size());
+        Assertions.assertEquals(2L, responsePage.getRecords().get(0).getId());
+    }
+
+    @Test
+    void shouldCopyRequestOntoEntity() {
+        FlinkAppCreateRequest request = new FlinkAppCreateRequest();
+        request.setJobName("sql-job");
+        request.setTeamId(100L);
+
+        FlinkApplication app = new FlinkApplication();
+        DtoAssembler.copy(request, app);
+
+        Assertions.assertEquals("sql-job", app.getJobName());
+        Assertions.assertEquals(100L, app.getTeamId());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssemblerTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssemblerTest.java
new file mode 100644
index 0000000..0e1df07
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/assembler/FlinkApplicationAssemblerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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 org.apache.streampark.console.core.assembler;
+
+import org.apache.streampark.console.core.entity.FlinkApplication;
+import org.apache.streampark.console.core.metrics.flink.JobsOverview;
+import org.apache.streampark.console.core.request.flink.FlinkAppCreateRequest;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+import org.apache.streampark.console.core.response.flink.FlinkAppDashboardResponse;
+import org.apache.streampark.console.core.response.flink.FlinkAppResponse;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+class FlinkApplicationAssemblerTest {
+
+    @Test
+    void shouldConvertCreateRequestToEntity() {
+        FlinkAppCreateRequest request = new FlinkAppCreateRequest();
+        request.setTeamId(100001L);
+        request.setJobName("demo");
+        request.setJobType(2);
+        request.setDeployMode(4);
+
+        FlinkApplication app = FlinkApplicationAssembler.toEntity(request);
+
+        Assertions.assertNotNull(app);
+        Assertions.assertEquals(100001L, app.getTeamId());
+        Assertions.assertEquals("demo", app.getJobName());
+        Assertions.assertEquals(2, app.getJobType());
+        Assertions.assertEquals(4, app.getDeployMode());
+    }
+
+    @Test
+    void shouldConvertStartRequestToEntity() {
+        FlinkAppStartRequest request = new FlinkAppStartRequest();
+        request.setId(1L);
+        request.setRestoreOrTriggerSavepoint(true);
+        request.setSavepointPath("/tmp/sp");
+        request.setAllowNonRestored(true);
+
+        FlinkApplication app = FlinkApplicationAssembler.toEntity(request);
+
+        Assertions.assertEquals(1L, app.getId());
+        Assertions.assertTrue(app.getRestoreOrTriggerSavepoint());
+        Assertions.assertEquals("/tmp/sp", app.getSavepointPath());
+        Assertions.assertTrue(app.getAllowNonRestored());
+    }
+
+    @Test
+    void shouldConvertEntityToResponse() {
+        FlinkApplication app = new FlinkApplication();
+        app.setId(10L);
+        app.setJobName("sql-job");
+        app.setState(0);
+
+        FlinkAppResponse response = FlinkApplicationAssembler.toResponse(app);
+
+        Assertions.assertNotNull(response);
+        Assertions.assertEquals(10L, response.getId());
+        Assertions.assertEquals("sql-job", response.getJobName());
+        Assertions.assertEquals(0, response.getState());
+    }
+
+    @Test
+    void shouldConvertDashboardMapToResponse() {
+        JobsOverview.Task task = new JobsOverview.Task();
+        task.setTotal(5);
+        task.setRunning(2);
+
+        Map<String, Serializable> dashboardMap = new HashMap<>();
+        dashboardMap.put("task", task);
+        dashboardMap.put("jmMemory", 1024);
+        dashboardMap.put("tmMemory", 2048);
+        dashboardMap.put("totalTM", 3);
+        dashboardMap.put("availableSlot", 8);
+        dashboardMap.put("totalSlot", 12);
+        dashboardMap.put("runningJob", 2);
+
+        FlinkAppDashboardResponse response = FlinkApplicationAssembler.toDashboardResponse(dashboardMap);
+
+        Assertions.assertNotNull(response);
+        Assertions.assertEquals(5, response.getTask().getTotal());
+        Assertions.assertEquals(1024, response.getJmMemory());
+        Assertions.assertEquals(2, response.getRunningJob());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/ApiTypeScriptGeneratorTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/ApiTypeScriptGeneratorTest.java
new file mode 100644
index 0000000..d0926fb
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/ApiTypeScriptGeneratorTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.core.bean.ApiContractDocument;
+import org.apache.streampark.console.core.bean.ApiContractDocument.ApiEndpointDescriptor;
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+import org.apache.streampark.console.core.request.common.IdRequest;
+import org.apache.streampark.console.system.request.team.TeamCreateRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+class ApiTypeScriptGeneratorTest {
+
+    @Test
+    void shouldGenerateInterfacesFromContractDocument() {
+        ApiContractDocument document = new ApiContractDocument();
+        ApiEndpointDescriptor endpoint = new ApiEndpointDescriptor();
+        endpoint.setController("TeamController");
+        endpoint.setHandler("addTeam");
+        endpoint.setPath("/team/post");
+        endpoint.setHttpMethod("POST");
+        endpoint.setRequestType("TeamCreateRequest");
+        endpoint.setResponseDataType("Void");
+        document.setEndpoints(Collections.singletonList(endpoint));
+
+        Map<String, List<OpenAPISchema.Schema>> dtoSchemas = new LinkedHashMap<>();
+        dtoSchemas.put("TeamCreateRequest", RequestDtoSchemaBuilder.build(TeamCreateRequest.class, null,
+            RequestDtoSchemaBuilder.defaultTypeNames()));
+        dtoSchemas.put("IdRequest", RequestDtoSchemaBuilder.build(IdRequest.class, null,
+            RequestDtoSchemaBuilder.defaultTypeNames()));
+        document.setDtoSchemas(dtoSchemas);
+
+        String typescript = ApiTypeScriptGenerator.generate(document);
+
+        Assertions.assertTrue(typescript.contains("export interface TeamCreateRequest"));
+        Assertions.assertTrue(typescript.contains("export interface RestResponseBody"));
+        Assertions.assertTrue(typescript.contains("export const apiEndpoints"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilderTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilderTest.java
new file mode 100644
index 0000000..1746838
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/component/RequestDtoSchemaBuilderTest.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 org.apache.streampark.console.core.component;
+
+import org.apache.streampark.console.core.bean.OpenAPISchema;
+import org.apache.streampark.console.core.request.flink.FlinkAppStartRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+class RequestDtoSchemaBuilderTest {
+
+    @Test
+    void shouldBuildSchemaFromRequestDtoFields() {
+        List<OpenAPISchema.Schema> schemas = RequestDtoSchemaBuilder.build(
+            FlinkAppStartRequest.class,
+            null,
+            RequestDtoSchemaBuilder.defaultTypeNames());
+
+        Map<String, OpenAPISchema.Schema> byBindFor = schemas.stream()
+            .collect(java.util.stream.Collectors.toMap(OpenAPISchema.Schema::getBindFor, s -> s));
+
+        Assertions.assertTrue(byBindFor.containsKey("id"));
+        Assertions.assertTrue(byBindFor.containsKey("restoreOrTriggerSavepoint"));
+        Assertions.assertEquals("restoreFromSavepoint", byBindFor.get("restoreOrTriggerSavepoint").getName());
+    }
+
+    @Test
+    void shouldMarkNotNullFieldsAsRequired() {
+        List<OpenAPISchema.Schema> schemas = RequestDtoSchemaBuilder.build(
+            FlinkAppStartRequest.class,
+            null,
+            RequestDtoSchemaBuilder.defaultTypeNames());
+
+        Map<String, OpenAPISchema.Schema> byBindFor = schemas.stream()
+            .collect(java.util.stream.Collectors.toMap(OpenAPISchema.Schema::getBindFor, s -> s));
+
+        Assertions.assertTrue(byBindFor.get("id").isRequired());
+        Assertions.assertTrue(byBindFor.get("teamId").isRequired());
+        Assertions.assertFalse(byBindFor.get("savepointPath").isRequired());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkApplicationControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkApplicationControllerMvcTest.java
new file mode 100644
index 0000000..b5c470c
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkApplicationControllerMvcTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.core.enums.AppExistsStateEnum;
+import org.apache.streampark.console.core.service.ResourceService;
+import org.apache.streampark.console.core.service.application.ApplicationLogService;
+import org.apache.streampark.console.core.service.application.FlinkApplicationActionService;
+import org.apache.streampark.console.core.service.application.FlinkApplicationBackupService;
+import org.apache.streampark.console.core.service.application.FlinkApplicationInfoService;
+import org.apache.streampark.console.core.service.application.FlinkApplicationManageService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.mockito.ArgumentMatchers.any;
+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(FlinkApplicationController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class FlinkApplicationControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private FlinkApplicationManageService applicationManageService;
+
+    @MockBean
+    private FlinkApplicationActionService applicationActionService;
+
+    @MockBean
+    private FlinkApplicationInfoService applicationInfoService;
+
+    @MockBean
+    private FlinkApplicationBackupService backUpService;
+
+    @MockBean
+    private ApplicationLogService applicationLogService;
+
+    @MockBean
+    private ResourceService resourceService;
+
+    @Test
+    void checkNameShouldRejectBlankJobName() throws Exception {
+        mockMvc.perform(
+            post("/flink/app/check/name")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("teamId", "100000"))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+
+    @Test
+    void checkNameShouldReturnExistsState() throws Exception {
+        when(applicationInfoService.checkExists(any())).thenReturn(AppExistsStateEnum.IN_DB);
+
+        mockMvc.perform(
+            post("/flink/app/check/name")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("jobName", "demo")
+                .param("teamId", "100000"))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("success"))
+            .andExpect(jsonPath("$.data").value(AppExistsStateEnum.IN_DB.get()));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkClusterControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkClusterControllerMvcTest.java
new file mode 100644
index 0000000..6c07236
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkClusterControllerMvcTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.core.service.FlinkClusterService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(FlinkClusterController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class FlinkClusterControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private FlinkClusterService flinkClusterService;
+
+    @Test
+    void createShouldRejectMissingClusterName() throws Exception {
+        mockMvc.perform(
+            post("/flink/cluster/create")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("deployMode", "1"))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkEnvControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkEnvControllerMvcTest.java
new file mode 100644
index 0000000..77847fc
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/FlinkEnvControllerMvcTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.core.service.FlinkEnvService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(FlinkEnvController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class FlinkEnvControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private FlinkEnvService flinkEnvService;
+
+    @Test
+    void deleteShouldRejectMissingId() throws Exception {
+        mockMvc.perform(post("/flink/env/delete").contentType(MediaType.APPLICATION_FORM_URLENCODED))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/ProjectControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/ProjectControllerMvcTest.java
new file mode 100644
index 0000000..46e68c8
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/ProjectControllerMvcTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.core.service.ProjectService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(ProjectController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class ProjectControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private ProjectService projectService;
+
+    @Test
+    void getShouldRejectMissingTeamId() throws Exception {
+        mockMvc.perform(
+            post("/project/get")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("id", "1"))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/SettingControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/SettingControllerMvcTest.java
new file mode 100644
index 0000000..82035a8
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/controller/SettingControllerMvcTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.core.service.SettingService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(SettingController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class SettingControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private SettingService settingService;
+
+    @Test
+    void getShouldRejectBlankKey() throws Exception {
+        mockMvc.perform(
+            post("/setting/get")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("key", ""))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/AppScopedIdRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/AppScopedIdRequestValidationTest.java
new file mode 100644
index 0000000..9150922
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/AppScopedIdRequestValidationTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import org.apache.streampark.console.core.request.flink.FlinkAppIdRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class AppScopedIdRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void appScopedIdRequestShouldRequireIdAndTeamId() {
+        Set<ConstraintViolation<AppScopedIdRequest>> violations = validator.validate(new AppScopedIdRequest());
+        Assertions.assertEquals(2, violations.size());
+    }
+
+    @Test
+    void appTeamQueryRequestShouldRequireAppIdAndTeamId() {
+        AppTeamQueryRequest request = new AppTeamQueryRequest();
+        request.setTeamId(1L);
+        Set<ConstraintViolation<AppTeamQueryRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void flinkAppIdRequestShouldInheritAppScopedValidation() {
+        FlinkAppIdRequest request = new FlinkAppIdRequest();
+        request.setId(1L);
+        Set<ConstraintViolation<FlinkAppIdRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/CommonRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/CommonRequestValidationTest.java
new file mode 100644
index 0000000..adfdcc3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/common/CommonRequestValidationTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.core.request.common;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class CommonRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void idRequestShouldRequireId() {
+        Set<ConstraintViolation<IdRequest>> violations = validator.validate(new IdRequest());
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void teamScopedIdRequestShouldRequireTeamIdAndId() {
+        TeamScopedIdRequest request = new TeamScopedIdRequest();
+        request.setId(1L);
+        Set<ConstraintViolation<TeamScopedIdRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void sqlVerifyRequestShouldRequireCoreFields() {
+        Set<ConstraintViolation<SqlVerifyRequest>> violations = validator.validate(new SqlVerifyRequest());
+        Assertions.assertEquals(3, violations.size());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/flink/FlinkAppRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/flink/FlinkAppRequestValidationTest.java
new file mode 100644
index 0000000..7fd116e
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/flink/FlinkAppRequestValidationTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.streampark.console.core.request.flink;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class FlinkAppRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void createRequestShouldRequireCoreFields() {
+        FlinkAppCreateRequest request = new FlinkAppCreateRequest();
+        Set<ConstraintViolation<FlinkAppCreateRequest>> violations = validator.validate(request);
+        Assertions.assertTrue(violations.size() >= 5);
+    }
+
+    @Test
+    void createRequestShouldPassWithRequiredFields() {
+        FlinkAppCreateRequest request = new FlinkAppCreateRequest();
+        request.setTeamId(1L);
+        request.setJobType(2);
+        request.setDeployMode(4);
+        request.setVersionId(1L);
+        request.setAppType(2);
+        request.setJobName("demo");
+
+        Set<ConstraintViolation<FlinkAppCreateRequest>> violations = validator.validate(request);
+        Assertions.assertTrue(violations.isEmpty());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/setting/SettingRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/setting/SettingRequestValidationTest.java
new file mode 100644
index 0000000..9de7db2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/setting/SettingRequestValidationTest.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 org.apache.streampark.console.core.request.setting;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class SettingRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void getRequestShouldRequireKey() {
+        Set<ConstraintViolation<SettingGetRequest>> violations = validator.validate(new SettingGetRequest());
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void emailRequestShouldRequireHostAndFrom() {
+        Set<ConstraintViolation<SettingEmailRequest>> violations = validator.validate(new SettingEmailRequest());
+        Assertions.assertEquals(2, violations.size());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/spark/SparkAppRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/spark/SparkAppRequestValidationTest.java
new file mode 100644
index 0000000..d03eb6f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/spark/SparkAppRequestValidationTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.streampark.console.core.request.spark;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class SparkAppRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void createRequestShouldRequireCoreFields() {
+        Set<ConstraintViolation<SparkAppCreateRequest>> violations = validator.validate(new SparkAppCreateRequest());
+        Assertions.assertTrue(violations.size() >= 5);
+    }
+
+    @Test
+    void checkNameRequestShouldRequireAppName() {
+        SparkAppCheckNameRequest request = new SparkAppCheckNameRequest();
+        request.setTeamId(1L);
+        Set<ConstraintViolation<SparkAppCheckNameRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void startRequestShouldRequireIdAndTeamId() {
+        Set<ConstraintViolation<SparkAppStartRequest>> violations = validator.validate(new SparkAppStartRequest());
+        Assertions.assertEquals(2, violations.size());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/sql/SqlRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/sql/SqlRequestValidationTest.java
new file mode 100644
index 0000000..6f05c0d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/request/sql/SqlRequestValidationTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.apache.streampark.console.core.request.sql;
+
+import org.apache.streampark.console.core.request.flink.FlinkSqlDeleteRequest;
+import org.apache.streampark.console.core.request.flink.FlinkSqlGetRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlDeleteRequest;
+import org.apache.streampark.console.core.request.spark.SparkSqlGetRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class SqlRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void flinkSqlDeleteShouldRequireIdAppIdAndTeamId() {
+        Set<ConstraintViolation<FlinkSqlDeleteRequest>> violations = validator.validate(new FlinkSqlDeleteRequest());
+        Assertions.assertEquals(3, violations.size());
+    }
+
+    @Test
+    void flinkSqlGetShouldRequireIdAppIdAndTeamId() {
+        FlinkSqlGetRequest request = new FlinkSqlGetRequest();
+        request.setAppId(1L);
+        request.setTeamId(2L);
+        Set<ConstraintViolation<FlinkSqlGetRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void sparkSqlDeleteShouldRequireSqlAppIdAndTeamId() {
+        Set<ConstraintViolation<SparkSqlDeleteRequest>> violations = validator.validate(new SparkSqlDeleteRequest());
+        Assertions.assertEquals(3, violations.size());
+    }
+
+    @Test
+    void sparkSqlGetShouldRequireIdAppIdAndTeamId() {
+        SparkSqlGetRequest request = new SparkSqlGetRequest();
+        request.setAppId(1L);
+        request.setTeamId(2L);
+        Set<ConstraintViolation<SparkSqlGetRequest>> violations = validator.validate(request);
+        Assertions.assertFalse(violations.isEmpty());
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/AccessTokenServiceTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/AccessTokenServiceTest.java
index ad80292..27131c3 100644
--- a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/AccessTokenServiceTest.java
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/AccessTokenServiceTest.java
@@ -19,13 +19,13 @@
 
 import org.apache.streampark.console.SpringUnitTestBase;
 import org.apache.streampark.console.base.domain.RestRequest;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.system.authentication.JWTToken;
 import org.apache.streampark.console.system.authentication.JWTUtil;
 import org.apache.streampark.console.system.entity.AccessToken;
 import org.apache.streampark.console.system.entity.User;
 import org.apache.streampark.console.system.service.AccessTokenService;
 import org.apache.streampark.console.system.service.UserService;
+import org.apache.streampark.console.system.service.result.AccessTokenCreateResult;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.junit.jupiter.api.Assertions;
@@ -43,12 +43,13 @@
     @Test
     void testCrudToken() throws Exception {
         Long mockUserId = 100000L;
-        RestResponse restResponse = accessTokenService.create(mockUserId, "");
-        Assertions.assertNotNull(restResponse);
-        Assertions.assertInstanceOf(AccessToken.class, restResponse.get("data"));
+        AccessTokenCreateResult createResult = accessTokenService.create(mockUserId, "");
+        Assertions.assertNotNull(createResult);
+        Assertions.assertTrue(createResult.isCreated());
+        Assertions.assertInstanceOf(AccessToken.class, createResult.getAccessToken());
 
         // verify
-        AccessToken accessToken = (AccessToken) restResponse.get("data");
+        AccessToken accessToken = createResult.getAccessToken();
         LOG.info(accessToken.getToken());
         JWTToken jwtToken = new JWTToken(JWTUtil.decrypt(accessToken.getToken()));
         LOG.info(jwtToken.getToken());
@@ -71,9 +72,7 @@
 
         // toggle
         Long tokenId = accessToken.getId();
-        RestResponse toggleTokenResp = accessTokenService.toggle(tokenId);
-        Assertions.assertNotNull(toggleTokenResp);
-        Assertions.assertTrue((Boolean) toggleTokenResp.get("data"));
+        Assertions.assertTrue(accessTokenService.toggle(tokenId));
 
         // get
         AccessToken afterToggle = accessTokenService.getByUserId(mockUserId);
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
index 46cfac0..d9f00f4 100644
--- a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
@@ -18,7 +18,6 @@
 package org.apache.streampark.console.core.service;
 
 import org.apache.streampark.console.SpringUnitTestBase;
-import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.entity.Resource;
 import org.apache.streampark.console.core.enums.EngineTypeEnum;
@@ -28,15 +27,13 @@
 import org.apache.streampark.console.core.service.application.FlinkApplicationManageService;
 import org.apache.streampark.console.system.entity.User;
 import org.apache.streampark.console.system.service.UserService;
+import org.apache.streampark.console.system.service.result.UserUpdateResult;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Collections;
-import java.util.Map;
-
 /** org.apache.streampark.console.core.service.UserServiceTest. */
 @Transactional
 class UserServiceTest extends SpringUnitTestBase {
@@ -51,7 +48,6 @@
     private ResourceService resourceService;
 
     @Test
-    @SuppressWarnings("unchecked")
     void testLockUser() throws Exception {
         User user = new User();
         user.setUsername("test");
@@ -62,16 +58,12 @@
         userService.createUser(user);
         // lock user
         user.setStatus(User.STATUS_LOCK);
-        Map<String, Object> data = (Map<String, Object>) userService
-            .updateUser(user)
-            .getOrDefault(RestResponse.DATA_KEY, Collections.emptyMap());
-        Assertions.assertNotEquals(true, data.get("needTransferResource"));
+        UserUpdateResult data = userService.updateUser(user);
+        Assertions.assertNotEquals(Boolean.TRUE, data == null ? null : data.isNeedTransferResource());
         // unlock user
         user.setStatus(User.STATUS_VALID);
-        Map<String, Object> data1 = (Map<String, Object>) userService
-            .updateUser(user)
-            .getOrDefault(RestResponse.DATA_KEY, Collections.emptyMap());
-        Assertions.assertNotEquals(true, data1.get("needTransferResource"));
+        UserUpdateResult data1 = userService.updateUser(user);
+        Assertions.assertNotEquals(Boolean.TRUE, data1 == null ? null : data1.isNeedTransferResource());
 
         Resource resource = new Resource();
         resource.setResourceName("test");
@@ -82,10 +74,8 @@
         resourceService.save(resource);
         // lock user when has resource
         user.setStatus(User.STATUS_LOCK);
-        Map<String, Object> data2 = (Map<String, Object>) userService
-            .updateUser(user)
-            .getOrDefault(RestResponse.DATA_KEY, Collections.emptyMap());
-        Assertions.assertEquals(true, data2.get("needTransferResource"));
+        UserUpdateResult data2 = userService.updateUser(user);
+        Assertions.assertEquals(Boolean.TRUE, data2.isNeedTransferResource());
     }
 
     @Test
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/alert/AlertServiceTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/alert/AlertServiceTest.java
index 7099b3b..c2118a5 100644
--- a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/alert/AlertServiceTest.java
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/alert/AlertServiceTest.java
@@ -20,7 +20,6 @@
 import org.apache.streampark.common.util.DateUtils;
 import org.apache.streampark.common.util.YarnUtils;
 import org.apache.streampark.console.base.util.FreemarkerUtils;
-import org.apache.streampark.console.core.bean.AlertConfigParams;
 import org.apache.streampark.console.core.bean.AlertDingTalkParams;
 import org.apache.streampark.console.core.bean.AlertLarkParams;
 import org.apache.streampark.console.core.bean.AlertTemplate;
@@ -28,6 +27,7 @@
 import org.apache.streampark.console.core.bean.EmailConfig;
 import org.apache.streampark.console.core.entity.FlinkApplication;
 import org.apache.streampark.console.core.enums.FlinkAppStateEnum;
+import org.apache.streampark.console.core.request.alert.AlertConfigRequest;
 import org.apache.streampark.console.core.service.alert.impl.DingTalkAlertNotifyServiceImpl;
 import org.apache.streampark.console.core.service.alert.impl.LarkAlertNotifyServiceImpl;
 import org.apache.streampark.console.core.service.alert.impl.WeComAlertNotifyServiceImpl;
@@ -54,7 +54,7 @@
 class AlertServiceTest {
 
     AlertTemplate alertTemplate;
-    AlertConfigParams params = new AlertConfigParams();
+    AlertConfigRequest params = new AlertConfigRequest();
     ObjectMapper mapper = new ObjectMapper();
     RestTemplate restTemplate = new RestTemplate();
     private Template template;
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/assembler/UserAssemblerTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/assembler/UserAssemblerTest.java
new file mode 100644
index 0000000..fc735b3
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/assembler/UserAssemblerTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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 org.apache.streampark.console.system.assembler;
+
+import org.apache.streampark.console.core.enums.LoginTypeEnum;
+import org.apache.streampark.console.core.enums.UserTypeEnum;
+import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.response.user.UserResponse;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+class UserAssemblerTest {
+
+    @Test
+    void shouldExcludeSensitiveFieldsFromResponse() {
+        User user = new User();
+        user.setUserId(1L);
+        user.setUsername("admin");
+        user.setPassword("secret");
+        user.setSalt("salt");
+        user.setEmail("admin@example.com");
+        user.setUserType(UserTypeEnum.USER);
+        user.setLoginType(LoginTypeEnum.PASSWORD);
+
+        UserResponse response = UserAssembler.toResponse(user);
+
+        Assertions.assertEquals("admin", response.getUsername());
+        Assertions.assertEquals("admin@example.com", response.getEmail());
+
+        var fieldNames = Arrays.stream(UserResponse.class.getDeclaredFields())
+            .map(java.lang.reflect.Field::getName)
+            .collect(Collectors.toSet());
+        Assertions.assertFalse(fieldNames.contains("password"));
+        Assertions.assertFalse(fieldNames.contains("salt"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/PassportControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/PassportControllerMvcTest.java
new file mode 100644
index 0000000..ae344b2
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/PassportControllerMvcTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.streampark.console.system.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.base.web.FormOrJsonArgumentResolver;
+import org.apache.streampark.console.system.security.Authenticator;
+import org.apache.streampark.console.system.service.UserService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(PassportController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import({GlobalExceptionHandler.class, FormOrJsonArgumentResolver.class, PassportControllerMvcTest.MvcTestConfig.class})
+class PassportControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private UserService userService;
+
+    @MockBean
+    private Authenticator authenticator;
+
+    @org.springframework.boot.test.context.TestConfiguration
+    static class MvcTestConfig implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer {
+
+        @Autowired
+        private FormOrJsonArgumentResolver formOrJsonArgumentResolver;
+
+        @Override
+        public void addArgumentResolvers(
+                                         java.util.List<org.springframework.web.method.support.HandlerMethodArgumentResolver> resolvers) {
+            resolvers.add(formOrJsonArgumentResolver);
+        }
+    }
+
+    @Test
+    void signinShouldReturnLegacyFailureCode() throws Exception {
+        mockMvc.perform(
+            post("/passport/signin")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("username", ""))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.code").value(0));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/RoleControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/RoleControllerMvcTest.java
new file mode 100644
index 0000000..6c8575d
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/RoleControllerMvcTest.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 org.apache.streampark.console.system.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.system.service.RoleMenuService;
+import org.apache.streampark.console.system.service.RoleService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(RoleController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class RoleControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private RoleService roleService;
+
+    @MockBean
+    private RoleMenuService roleMenuService;
+
+    @Test
+    void checkRoleNameShouldRejectBlankName() throws Exception {
+        mockMvc.perform(
+            post("/role/check/name")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("roleName", ""))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/TeamControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/TeamControllerMvcTest.java
new file mode 100644
index 0000000..e5ac19f
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/TeamControllerMvcTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.apache.streampark.console.system.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.base.web.FormOrJsonArgumentResolver;
+import org.apache.streampark.console.system.service.TeamService;
+
+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.context.annotation.Import;
+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.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(TeamController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import({GlobalExceptionHandler.class, FormOrJsonArgumentResolver.class, TeamControllerMvcTest.MvcTestConfig.class})
+class TeamControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private TeamService teamService;
+
+    @org.springframework.boot.test.context.TestConfiguration
+    static class MvcTestConfig implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer {
+
+        @Autowired
+        private FormOrJsonArgumentResolver formOrJsonArgumentResolver;
+
+        @Override
+        public void addArgumentResolvers(
+                                         java.util.List<org.springframework.web.method.support.HandlerMethodArgumentResolver> resolvers) {
+            resolvers.add(formOrJsonArgumentResolver);
+        }
+    }
+
+    @Test
+    void addTeamShouldAcceptFormUrlEncodedBody() throws Exception {
+        doNothing().when(teamService).createTeam(any());
+
+        mockMvc.perform(
+            post("/team/post")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("teamName", "demo")
+                .param("description", "test"))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("success"));
+    }
+
+    @Test
+    void addTeamShouldAcceptJsonBody() throws Exception {
+        doNothing().when(teamService).createTeam(any());
+
+        mockMvc.perform(
+            post("/team/post")
+                .contentType(MediaType.APPLICATION_JSON)
+                .content("{\"teamName\":\"demo\",\"description\":\"test\"}"))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("success"));
+    }
+
+    @Test
+    void addTeamShouldRejectBlankTeamNameJson() throws Exception {
+        mockMvc.perform(
+            post("/team/post")
+                .contentType(MediaType.APPLICATION_JSON)
+                .content("{\"teamName\":\"\",\"description\":\"test\"}"))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/UserControllerMvcTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/UserControllerMvcTest.java
new file mode 100644
index 0000000..990d970
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/controller/UserControllerMvcTest.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 org.apache.streampark.console.system.controller;
+
+import org.apache.streampark.console.base.handler.GlobalExceptionHandler;
+import org.apache.streampark.console.system.service.TeamService;
+import org.apache.streampark.console.system.service.UserService;
+
+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.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+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(UserController.class)
+@AutoConfigureMockMvc(addFilters = false)
+@Import(GlobalExceptionHandler.class)
+class UserControllerMvcTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private UserService userService;
+
+    @MockBean
+    private TeamService teamService;
+
+    @Test
+    void checkUserNameShouldRejectBlankUsername() throws Exception {
+        mockMvc.perform(
+            post("/user/check/name")
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .param("username", ""))
+            .andExpect(status().isBadRequest())
+            .andExpect(jsonPath("$.status").value("error"));
+    }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/request/SystemRequestValidationTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/request/SystemRequestValidationTest.java
new file mode 100644
index 0000000..0ec1a2a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/system/request/SystemRequestValidationTest.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 org.apache.streampark.console.system.request;
+
+import org.apache.streampark.console.system.request.member.MemberCreateRequest;
+import org.apache.streampark.console.system.request.team.TeamCreateRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import java.util.Set;
+
+class SystemRequestValidationTest {
+
+    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+
+    @Test
+    void teamCreateRequestShouldRequireTeamName() {
+        Set<ConstraintViolation<TeamCreateRequest>> violations = validator.validate(new TeamCreateRequest());
+        Assertions.assertFalse(violations.isEmpty());
+    }
+
+    @Test
+    void memberCreateRequestShouldRequireCoreFields() {
+        Set<ConstraintViolation<MemberCreateRequest>> violations = validator.validate(new MemberCreateRequest());
+        Assertions.assertTrue(violations.size() >= 3);
+    }
+}
diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt
index 8f7dcb6..26f663a 100644
--- a/tools/dependencies/known-dependencies.txt
+++ b/tools/dependencies/known-dependencies.txt
@@ -36,6 +36,7 @@
 checker-qual-3.5.0.jar
 chill-java-0.9.5.jar
 chill_2.12-0.9.5.jar
+classmate-1.5.1.jar
 commons-beanutils-1.9.3.jar
 commons-cli-1.5.0.jar
 commons-codec-1.15.jar
@@ -107,6 +108,7 @@
 hadoop-yarn-api-3.2.0.jar
 hadoop-yarn-client-3.2.0.jar
 hadoop-yarn-common-3.2.0.jar
+hibernate-validator-6.2.5.Final.jar
 hive-storage-api-2.7.2.jar
 hk2-api-2.6.1.jar
 hk2-locator-2.6.1.jar
@@ -349,6 +351,7 @@
 spring-boot-starter-jdbc-2.7.11.jar
 spring-boot-starter-json-2.7.11.jar
 spring-boot-starter-quartz-2.7.11.jar
+spring-boot-starter-validation-2.7.11.jar
 spring-boot-starter-undertow-2.7.11.jar
 spring-boot-starter-web-2.7.11.jar
 spring-boot-starter-websocket-2.7.11.jar
diff --git a/tools/openapi/export-api-schemas.sh b/tools/openapi/export-api-schemas.sh
new file mode 100755
index 0000000..5fcc539
--- /dev/null
+++ b/tools/openapi/export-api-schemas.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+#
+# 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.
+#
+
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+OUTPUT_DIR="${ROOT_DIR}/tools/openapi/generated"
+JSON_FILE="${OUTPUT_DIR}/api-contracts.json"
+TS_FILE="${OUTPUT_DIR}/api-types.ts"
+
+mkdir -p "${OUTPUT_DIR}"
+
+echo "Running API contract export tests..."
+(
+  cd "${ROOT_DIR}"
+  ./mvnw -q -pl streampark-console/streampark-console-service \
+    -Dtest=ApiTypeScriptGeneratorTest \
+    -Dspotless.check.skip=true \
+    -Drat.skip=true \
+    -Dcheckstyle.skip=true \
+    test
+)
+
+cat > "${TS_FILE}" <<'EOF'
+// Placeholder generated by export-api-schemas.sh.
+// Run the console and call POST /openapi/contracts/typescript for a live export,
+// or extend ApiSchemaExportMain to write files during build.
+export {};
+EOF
+
+echo "API schema tooling verified. Output directory: ${OUTPUT_DIR}"
+echo "Use POST /openapi/contracts and POST /openapi/contracts/typescript at runtime for full export."