[ISSUE #26] CRUD the basic tables of Topic, Group, GroupMember, and Operation (#28) (#34)

* refactor: add dependency of console module and move controllers into console module.

* fix: add logback config, fix application-dev.yml and move `</dependencyManagement>` to root `pom.xml` as pointed out in PR#19.

* FirstCommit

* remerge

* first improve

* second improve

* third improve

* fourth improve

* fourth improve

* fourth improve

* Update and rename EventmeshConsoleApplication.java to EventMeshDashboardApplication.java

* rename this starter class file to EventMeshDashboardApplication

* rename this starter class file to EventMeshDashboardApplication

* change some resource file

* improve name

* improve name

* Modify the fields of the synchronized log table

* improve name

* improve name

---------

Co-authored-by: zzx <142965157+zzxxiansheng@users.noreply.github.com>
Co-authored-by: lambert@arch <lambertrao@outlook.com>
diff --git a/eventmesh-dashboard-console/pom.xml b/eventmesh-dashboard-console/pom.xml
index fa06c45..ddf6595 100644
--- a/eventmesh-dashboard-console/pom.xml
+++ b/eventmesh-dashboard-console/pom.xml
@@ -69,6 +69,20 @@
             <artifactId>mysql-connector-j</artifactId>
             <scope>runtime</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aspects</artifactId>
+            <version>5.1.2.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
+
+
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/EventMeshDashboardApplication.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/EventMeshDashboardApplication.java
index 79fc03d..117dd06 100644
--- a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/EventMeshDashboardApplication.java
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/EventMeshDashboardApplication.java
@@ -19,19 +19,21 @@
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 @SpringBootApplication
-@EnableScheduling
-@ComponentScan({"org.apache.eventmesh.dashboard.service", "org.apache.eventmesh.dashboard.console"})
+@EnableTransactionManagement
 public class EventMeshDashboardApplication {
 
     public static void main(String[] args) {
-        SpringApplication.run(EventMeshDashboardApplication.class, args);
-        log.info("{} Successfully booted.", EventMeshDashboardApplication.class.getSimpleName());
+        try {
+            SpringApplication.run(EventMeshDashboardApplication.class, args);
+            log.info("{} Successfully booted.", EventMeshDashboardApplication.class.getSimpleName());
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
     }
 }
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/annotation/EmLog.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/annotation/EmLog.java
new file mode 100644
index 0000000..efae3a5
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/annotation/EmLog.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.eventmesh.dashboard.console.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface EmLog {
+
+    String OprType() default "";
+
+    String OprTarget() default "";
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/group/GroupEntity.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/group/GroupEntity.java
new file mode 100644
index 0000000..c395bac
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/group/GroupEntity.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.eventmesh.dashboard.console.entity.group;
+
+import java.sql.Timestamp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class GroupEntity {
+    private Long id;
+
+    private Long clusterId;
+
+    private String name;
+
+    private Integer memberCount;
+
+    private String members;
+
+    private Integer type;
+
+    private String state;
+
+    private Timestamp createTime;
+
+    private Timestamp updateTime;
+
+
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/groupmember/GroupMemberEntity.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/groupmember/GroupMemberEntity.java
new file mode 100644
index 0000000..dbadc1e
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/groupmember/GroupMemberEntity.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.eventmesh.dashboard.console.entity.groupmember;
+
+import java.sql.Timestamp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class GroupMemberEntity {
+    private Long id;
+
+    private Long clusterId;
+
+    private String topicName;
+
+    private String groupName;
+
+    private String eventMeshUser;
+
+    private String state;
+
+    private Timestamp createTime;
+
+    private Timestamp updateTime;
+
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/log/LogEntity.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/log/LogEntity.java
new file mode 100644
index 0000000..ac7c30a
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/log/LogEntity.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.eventmesh.dashboard.console.entity.log;
+
+import java.sql.Timestamp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LogEntity {
+
+    private Long id;
+
+    private Long clusterId;
+
+    private String operationType;
+
+    private String targetType;
+
+    private Integer status;
+
+    private String content;
+
+    private Timestamp createTime;
+
+    private Timestamp endTime;
+
+    private String operationUser;
+
+    private String result;
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/topic/TopicEntity.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/topic/TopicEntity.java
new file mode 100644
index 0000000..6b4bd09
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/entity/topic/TopicEntity.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.eventmesh.dashboard.console.entity.topic;
+
+import java.sql.Timestamp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TopicEntity {
+    private Long id;
+
+    private Long clusterId;
+
+    private String topicName;
+
+    private String runtimeId;
+
+    private String storageId;
+
+    private Long retentionMs;
+
+    private Integer type;
+
+    private String description;
+
+    private Timestamp createTime;
+
+    private Timestamp updateTime;
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/log/OprLog.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/log/OprLog.java
new file mode 100644
index 0000000..9df7e23
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/log/OprLog.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.log;
+
+import org.apache.eventmesh.dashboard.console.annotation.EmLog;
+import org.apache.eventmesh.dashboard.console.entity.log.LogEntity;
+import org.apache.eventmesh.dashboard.console.service.log.LogService;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.sql.Timestamp;
+import java.util.Objects;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ClassUtils;
+
+@Aspect
+@Service
+public class OprLog implements Ordered, ApplicationContextAware {
+
+    private int order = LOWEST_PRECEDENCE - 1000; // Specify the order of execution
+
+    private LogService logService;
+
+    private ApplicationContext applicationContext;
+
+
+    @Pointcut("within(org.apache.eventmesh.dashboard.console.service..*)")
+    public void pointCut() {
+    }
+
+
+    @Around("pointCut()")
+    public Object logStart(ProceedingJoinPoint joinPoint) throws Throwable {
+        if (Objects.isNull(this.logService)) {
+            this.logService = applicationContext.getBean(LogService.class);
+        }
+        EmLog declaredAnnotation = this.getTargetEmlog(joinPoint);
+        //Get the Emlog annotation on the method
+        if (Objects.isNull(declaredAnnotation)) {
+            return joinPoint.proceed();
+        }
+        LogEntity logEntity = this.productLoEntity(declaredAnnotation, joinPoint);
+        logService.addLog(logEntity);
+        logEntity.setEndTime(new Timestamp(System.currentTimeMillis()));
+        Object proceed = null;
+        try {
+            proceed = joinPoint.proceed();
+            logEntity.setStatus(2);
+            logEntity.setResult(Objects.isNull(proceed) ? "" : proceed.toString());
+            return proceed;
+        } catch (Throwable e) {
+            logEntity.setStatus(3);
+            throw new RuntimeException(e);
+        } finally {
+            logEntity.setResult(proceed.toString());
+            logService.updateLog(logEntity);
+        }
+
+
+    }
+
+    public LogEntity productLoEntity(EmLog declaredAnnotation, ProceedingJoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
+        LogEntity logEntity = new LogEntity();
+        Object[] args = joinPoint.getArgs();
+        Object model = args[0];
+        //Obtaining the Input Parameter of the Operation Method (Specified as the First)
+        Field clusterPhyId = model.getClass().getDeclaredField("clusterId");
+        clusterPhyId.setAccessible(true);
+        Long opClusterPhyId = (Long) clusterPhyId.get(model);
+        //The clusterId is obtained from the parameter object, and the operation is described as the object itself
+        logEntity.setClusterId(opClusterPhyId);
+        logEntity.setContent(model.toString());
+        logEntity.setOperationType(declaredAnnotation.OprType());
+        logEntity.setTargetType(declaredAnnotation.OprTarget());
+        logEntity.setStatus(1);
+        logEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));
+        return logEntity;
+    }
+
+    public EmLog getTargetEmlog(ProceedingJoinPoint joinPoint) {
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Method method = signature.getMethod();
+        Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, joinPoint.getTarget().getClass());
+        EmLog declaredAnnotation = mostSpecificMethod.getAnnotation(EmLog.class);
+        return declaredAnnotation;
+    }
+
+    @Override
+    public int getOrder() {
+        return order;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/group/OprGroupMapper.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/group/OprGroupMapper.java
new file mode 100644
index 0000000..f1a91ed
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/group/OprGroupMapper.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.eventmesh.dashboard.console.mapper.group;
+
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * operate Group mapper
+ **/
+@Mapper
+public interface OprGroupMapper {
+
+    @Insert("INSERT INTO `group` (cluster_id, name, member_count, members, type, state)"
+        + "VALUE (#{clusterId},#{name},#{memberCount},#{members},#{type},#{state}) "
+        + "on duplicate key update is_delete=0")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    void addGroup(GroupEntity groupEntity);
+
+    @Update("update `group`set member_count=#{memberCount},"
+        + "members=#{members},type=#{type},state=#{state} where id=#{id}")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    Integer updateGroup(GroupEntity groupEntity);
+
+    @Delete("update `group` set  is_delete=1 where id=#{id}")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    Integer deleteGroup(GroupEntity groupEntity);
+
+    @Select("select * from `group` where cluster_id=#{clusterId} and name=#{name} and is_delete=0")
+    GroupEntity selectGroupByUnique(GroupEntity groupEntity);
+
+    @Select("select * from `group` where id=#{id} and is_delete=0")
+    GroupEntity selectGroupById(GroupEntity groupEntity);
+
+    @Select("<script>"
+        + "select * from `group`"
+        + "<where>"
+        + "<if test='clusterId != null'>"
+        + "cluster_id=#{clusterId}"
+        + "</if>"
+        + "<if test='name != null'>"
+        + "and name like concat('%',#{name},'%')"
+        + "</if>"
+        + "and is_delete=0"
+        + "</where>"
+        + "</script>")
+    List<GroupEntity> selectGroup(GroupEntity groupEntity);
+
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/groupmember/OprGroupMemberMapper.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/groupmember/OprGroupMemberMapper.java
new file mode 100644
index 0000000..3179eff
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/groupmember/OprGroupMemberMapper.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.mapper.groupmember;
+
+
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * operate GroupMember mapper
+ **/
+
+@Mapper
+public interface OprGroupMemberMapper {
+
+    @Select("select * from group_member where cluster_id=#{clusterId} and is_delete=0")
+    List<GroupMemberEntity> getGroupByClusterId(GroupMemberEntity groupMemberEntity);
+
+    @Insert("insert into group_member (cluster_id, topic_name, group_name, eventmesh_user,state)"
+        + " VALUE (#{clusterId},#{topicName},#{groupName},#{eventMeshUser},#{state})"
+        + "on duplicate key update is_delete=0")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    void addGroupMember(GroupMemberEntity groupMemberEntity);
+
+    @Update("update group_member set state=#{state} where id=#{id}")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    void updateGroupMember(GroupMemberEntity groupMemberEntity);
+
+    @Delete("update group_member set is_delete=1 where id=#{id} ")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    GroupMemberEntity deleteGroupMember(GroupMemberEntity groupMemberEntity);
+
+    @Select("select * from group_member where cluster_id=#{clusterId} and group_name=#{groupName} and topic_name=#{topicName} and is_delete=0")
+    GroupMemberEntity selectGroupMemberByUnique(GroupMemberEntity groupMemberEntity);
+
+    @Select("select * from group_member where id=#{id} and is_delete=0")
+    GroupMemberEntity selectGroupMemberById(GroupMemberEntity groupMemberEntity);
+
+    @Select("<script>"
+        + "select * from group_member"
+        + "<where>"
+        + "<if test='clusterId != null'>"
+        + "cluster_id=#{clusterId}"
+        + "</if>"
+        + "<if test='groupName != null'>"
+        + "and group_name=#{groupName}"
+        + "</if>"
+        + "<if test='topicName != null'>"
+        + "and topic_name=#{topicName}"
+        + "</if>"
+        + "</where>"
+        + "and is_delete=0"
+        + "</script>")
+    List<GroupMemberEntity> selectMember(GroupMemberEntity groupMemberEntity);
+
+    @Update("update group_member set state=#{state} where topic_name=#{topicName}")
+    void updateMemberByTopic(GroupMemberEntity groupMemberEntity);
+}
\ No newline at end of file
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/log/OprLogMapper.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/log/OprLogMapper.java
new file mode 100644
index 0000000..d6c96f7
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/log/OprLogMapper.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.eventmesh.dashboard.console.mapper.log;
+
+import org.apache.eventmesh.dashboard.console.entity.log.LogEntity;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.SelectKey;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * operate operationLog mapper
+ **/
+@Mapper
+public interface OprLogMapper {
+
+    @Select("<script>"
+        + "select * from operation_log"
+        + "<where>"
+        + "<if test='targetType!=null'>"
+        + "target_type=#{targetType}"
+        + "</if>"
+        + "<if test='operationUser!=null'>"
+        + "and operation_user=#{operationUser}"
+        + "</if>"
+        + "<if test='clusterId!=null'>"
+        + "and cluster_id=#{clusterId} "
+        + "</if>"
+        + "and is_delete=0"
+        + "</where>"
+        + "</script>")
+    List<LogEntity> getLogList(LogEntity logEntity);
+
+    @Insert("insert into operation_log ( cluster_id, operation_type,target_Type, description,operation_user,result_content)"
+        + "VALUE (#{clusterId},#{operationType},#{targetType},#{description},#{operationUser},#{resultContent})")
+    @SelectKey(keyColumn = "id", statement = {" select last_insert_id()"}, keyProperty = "id", before = false, resultType = Long.class)
+    Long addLog(LogEntity logEntity);
+
+    @Update("update operation_log set status=#{status} ,result_content=#{resultContent} where id=#{id}")
+    Integer updateLog(LogEntity logEntity);
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/topic/TopicMapper.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/topic/TopicMapper.java
new file mode 100644
index 0000000..8a396be
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/mapper/topic/TopicMapper.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.mapper.topic;
+
+
+import org.apache.eventmesh.dashboard.console.entity.topic.TopicEntity;
+
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * operate Topic mapper
+ **/
+@Mapper
+public interface TopicMapper {
+
+    @Select("<script>"
+        + "select * from topic"
+        + "<where>"
+        + "<if test='topicName!=null'>"
+        + "and topic_name=#{topicName}"
+        + "</if>"
+        + "<if test='clusterId!=null'>"
+        + "and cluster_id=#{clusterId} "
+        + "</if>"
+        + "and is_delete=0"
+        + "</where>"
+        + "</script>")
+    List<TopicEntity> getTopicList(TopicEntity topicEntity);
+
+    @Insert("INSERT INTO topic (cluster_id, topic_name, runtime_id, storage_id, retention_ms, type, description) "
+        + "VALUE (#{clusterId},#{topicName},#{runtimeId},#{storageId},#{retentionMs},#{type},#{description})"
+        + "on duplicate key update is_delete = 0")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    void addTopic(TopicEntity topicEntity);
+
+    @Update("update topic set type=#{type},description=#{description} where id=#{id}")
+    void updateTopic(TopicEntity topicEntity);
+
+    @Delete("update `topic` set is_delete=1 where id=#{id}")
+    void deleteTopic(TopicEntity topicEntity);
+
+    @Select("select * from topic where cluster_id=#{clusterId} and topic_name=#{topicName}")
+    TopicEntity selectTopicByUnique(TopicEntity topicEntity);
+
+    @Select("select * from topic where id=#{id}")
+    TopicEntity selectTopicById(TopicEntity topicEntity);
+
+}
\ No newline at end of file
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupService.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupService.java
new file mode 100644
index 0000000..e5a80c5
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupService.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.eventmesh.dashboard.console.service.group;
+
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+
+
+import java.util.List;
+
+/**
+ * operate Group Service
+ */
+
+public interface GroupService {
+
+    List<GroupEntity> getGroupByClusterId(GroupEntity groupEntity);
+
+    GroupEntity addGroup(GroupEntity groupEntity);
+
+    void updateGroup(GroupEntity groupEntity);
+
+    Integer deleteGroup(GroupEntity groupEntity);
+
+    GroupEntity selectGroup(GroupEntity groupEntity);
+
+    Integer insertMemberToGroup(GroupMemberEntity groupMemberEntity);
+
+    Integer deleteMemberFromGroup(GroupMemberEntity groupMemberEntity);
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupServiceImpl.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupServiceImpl.java
new file mode 100644
index 0000000..3647a5a
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/group/GroupServiceImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.service.group;
+
+import org.apache.eventmesh.dashboard.console.annotation.EmLog;
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+import org.apache.eventmesh.dashboard.console.mapper.group.OprGroupMapper;
+import org.apache.eventmesh.dashboard.console.service.groupmember.GroupMemberService;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class GroupServiceImpl implements GroupService {
+
+    @Autowired
+    OprGroupMapper oprGroupMapper;
+
+    @Autowired
+    GroupMemberService groupMemberService;
+
+    @EmLog(OprType = "search", OprTarget = "Group")
+    @Override
+    public List<GroupEntity> getGroupByClusterId(GroupEntity groupEntity) {
+        return oprGroupMapper.selectGroup(groupEntity);
+
+    }
+
+    @EmLog(OprType = "add", OprTarget = "Group")
+    @Override
+    public GroupEntity addGroup(GroupEntity groupEntity) {
+        oprGroupMapper.addGroup(groupEntity);
+        return groupEntity;
+    }
+
+    @Override
+    public void updateGroup(GroupEntity groupEntity) {
+        oprGroupMapper.updateGroup(groupEntity);
+    }
+
+    @Override
+    public Integer deleteGroup(GroupEntity groupEntity) {
+        return oprGroupMapper.deleteGroup(groupEntity);
+    }
+
+    @Override
+    public GroupEntity selectGroup(GroupEntity groupEntity) {
+        return oprGroupMapper.selectGroupById(groupEntity);
+    }
+
+    @Override
+    public Integer insertMemberToGroup(GroupMemberEntity groupMemberEntity) {
+        groupMemberService.addGroupMember(groupMemberEntity);
+        GroupEntity groupEntity = new GroupEntity();
+        groupEntity.setName(groupMemberEntity.getGroupName());
+        groupEntity.setClusterId(groupMemberEntity.getClusterId());
+        GroupEntity groupEntity1 = oprGroupMapper.selectGroupByUnique(groupEntity);
+        //^Obtain the group to which the member belongs
+        groupEntity1.setMembers(groupMemberEntity.getId() + "" + "," + groupEntity1.getMembers());
+        //Concatenate the members of the group
+        groupEntity1.setMemberCount(groupEntity1.getMemberCount() + 1);
+        groupEntity1.setUpdateTime(new Timestamp(System.currentTimeMillis()));
+        oprGroupMapper.updateGroup(groupEntity1);
+        return 1;
+        //Modify the group member information
+    }
+
+    @Override
+    public Integer deleteMemberFromGroup(GroupMemberEntity groupMemberEntity) {
+        groupMemberService.deleteGroupMember(groupMemberEntity);
+        GroupEntity groupEntity = new GroupEntity();
+        groupEntity.setName(groupMemberEntity.getGroupName());
+        groupEntity.setClusterId(groupMemberEntity.getClusterId());
+        GroupEntity groupEntity1 = oprGroupMapper.selectGroupByUnique(groupEntity);
+        //^Obtain the group to which the member belongs
+        groupEntity1.setMembers(groupEntity1.getMembers().replaceAll(groupMemberEntity.getId() + "" + ",", ""));
+        groupEntity1.setMemberCount(groupEntity1.getMemberCount() - 1);
+        groupEntity1.setUpdateTime(new Timestamp(System.currentTimeMillis()));
+        oprGroupMapper.updateGroup(groupEntity1);
+        return 1;
+    }
+
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberService.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberService.java
new file mode 100644
index 0000000..28f9516
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberService.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.eventmesh.dashboard.console.service.groupmember;
+
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+
+import java.util.List;
+
+/**
+ * Service About GroupMember
+ */
+public interface GroupMemberService {
+
+    List<GroupMemberEntity> getGroupMemberByClusterId(GroupMemberEntity groupMemberEntity);
+
+    void addGroupMember(GroupMemberEntity groupMemberEntity);
+
+    void updateGroupMember(GroupMemberEntity groupMemberEntity);
+
+    GroupMemberEntity deleteGroupMember(GroupMemberEntity groupMemberEntity);
+
+    GroupMemberEntity selectGroupMemberById(GroupMemberEntity groupMemberEntity);
+
+    List<GroupMemberEntity> selectGroupMemberByGroup(GroupEntity groupEntity);
+
+    List<GroupMemberEntity> selectAllMemberByTopic(GroupMemberEntity groupMemberEntity);
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberServiceImp.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberServiceImp.java
new file mode 100644
index 0000000..d50173e
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/groupmember/GroupMemberServiceImp.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.service.groupmember;
+
+import org.apache.eventmesh.dashboard.console.annotation.EmLog;
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+import org.apache.eventmesh.dashboard.console.mapper.groupmember.OprGroupMemberMapper;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class GroupMemberServiceImp implements GroupMemberService {
+
+    @Autowired
+    OprGroupMemberMapper oprGroupMemberMapper;
+
+    @Override
+    @EmLog(OprType = "View", OprTarget = "GroupMember")
+    public List<GroupMemberEntity> getGroupMemberByClusterId(GroupMemberEntity groupMemberEntity) {
+        return oprGroupMemberMapper.getGroupByClusterId(groupMemberEntity);
+    }
+
+    @Override
+    @EmLog(OprType = "add", OprTarget = "GroupMember")
+    public void addGroupMember(GroupMemberEntity groupMemberEntity) {
+        oprGroupMemberMapper.addGroupMember(groupMemberEntity);
+    }
+
+    @Override
+    public void updateGroupMember(GroupMemberEntity groupMemberEntity) {
+        oprGroupMemberMapper.updateGroupMember(groupMemberEntity);
+    }
+
+    @Override
+    public GroupMemberEntity deleteGroupMember(GroupMemberEntity groupMemberEntity) {
+        return oprGroupMemberMapper.deleteGroupMember(groupMemberEntity);
+    }
+
+    @Override
+    public GroupMemberEntity selectGroupMemberById(GroupMemberEntity groupMemberEntity) {
+        return oprGroupMemberMapper.selectGroupMemberById(groupMemberEntity);
+    }
+
+    @Override
+    public List<GroupMemberEntity> selectGroupMemberByGroup(GroupEntity groupEntity) {
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setGroupName(groupEntity.getName());
+        groupMemberEntity.setClusterId(groupEntity.getClusterId());
+        //Obtain a member who meets the conditions of a group
+        return oprGroupMemberMapper.selectMember(groupMemberEntity);
+    }
+
+    @Override
+    public List<GroupMemberEntity> selectAllMemberByTopic(GroupMemberEntity groupMemberEntity) {
+        List<GroupMemberEntity> groupMemberEntities = oprGroupMemberMapper.selectMember(groupMemberEntity);
+        return groupMemberEntities;
+    }
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogService.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogService.java
new file mode 100644
index 0000000..d496ae6
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogService.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.eventmesh.dashboard.console.service.log;
+
+import org.apache.eventmesh.dashboard.console.entity.log.LogEntity;
+
+import java.util.List;
+
+/**
+ *
+ * operation service
+ *
+ */
+
+public interface LogService {
+
+    List<LogEntity> getLogListByCluster(LogEntity logEntity);
+
+    Long addLog(LogEntity logEntity);
+
+    Integer updateLog(LogEntity logEntity);
+
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogServiceImpl.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogServiceImpl.java
new file mode 100644
index 0000000..7bd680b
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/log/LogServiceImpl.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.eventmesh.dashboard.console.service.log;
+
+import org.apache.eventmesh.dashboard.console.entity.log.LogEntity;
+import org.apache.eventmesh.dashboard.console.mapper.log.OprLogMapper;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LogServiceImpl implements LogService {
+
+    @Autowired
+    OprLogMapper oprLogMapper;
+
+    @Override
+    public List<LogEntity> getLogListByCluster(LogEntity logEntity) {
+
+        return oprLogMapper.getLogList(logEntity);
+    }
+
+    @Override
+    public Long addLog(LogEntity logEntity) {
+
+        return oprLogMapper.addLog(logEntity);
+    }
+
+    @Override
+    public Integer updateLog(LogEntity logEntity) {
+
+        return oprLogMapper.updateLog(logEntity);
+    }
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicService.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicService.java
new file mode 100644
index 0000000..95c8a32
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicService.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.eventmesh.dashboard.console.service.topic;
+
+import org.apache.eventmesh.dashboard.console.entity.topic.TopicEntity;
+
+import java.util.List;
+
+/**
+ * Service about Topic
+ */
+public interface TopicService {
+    List<TopicEntity> getTopicList(TopicEntity topicEntity);
+
+    void addTopic_plus(TopicEntity topicEntity);
+
+    void updateTopic(TopicEntity topicEntity);
+
+    void deleteTopicById(TopicEntity topicEntity);
+
+    TopicEntity selectTopicById(TopicEntity topicEntity);
+
+    TopicEntity selectTopicByUnique(TopicEntity topicEntity);
+
+    void deleteTopic(TopicEntity topicEntity);
+}
diff --git a/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicServiceImpl.java b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicServiceImpl.java
new file mode 100644
index 0000000..aa42e7b
--- /dev/null
+++ b/eventmesh-dashboard-console/src/main/java/org/apache/eventmesh/dashboard/console/service/topic/TopicServiceImpl.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.eventmesh.dashboard.console.service.topic;
+
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+import org.apache.eventmesh.dashboard.console.entity.topic.TopicEntity;
+import org.apache.eventmesh.dashboard.console.mapper.groupmember.OprGroupMemberMapper;
+import org.apache.eventmesh.dashboard.console.mapper.topic.TopicMapper;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TopicServiceImpl implements TopicService {
+
+    @Autowired
+    TopicMapper topicMapper;
+
+    @Autowired
+    OprGroupMemberMapper oprGroupMemberMapper;
+
+
+    @Override
+    public List<TopicEntity> getTopicList(TopicEntity topicEntity) {
+        return topicMapper.getTopicList(topicEntity);
+    }
+
+    @Override
+    public void addTopic_plus(TopicEntity topicEntity) {
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setTopicName(topicEntity.getTopicName());
+        groupMemberEntity.setState("active");
+        oprGroupMemberMapper.updateMemberByTopic(groupMemberEntity);
+        topicMapper.addTopic(topicEntity);
+    }
+
+    @Override
+    public void updateTopic(TopicEntity topicEntity) {
+        topicMapper.updateTopic(topicEntity);
+    }
+
+    @Override
+    public void deleteTopicById(TopicEntity topicEntity) {
+        topicMapper.deleteTopic(topicEntity);
+    }
+
+    @Override
+    public TopicEntity selectTopicById(TopicEntity topicEntity) {
+        return topicMapper.selectTopicById(topicEntity);
+    }
+
+    @Override
+    public TopicEntity selectTopicByUnique(TopicEntity topicEntity) {
+        return topicMapper.selectTopicByUnique(topicEntity);
+    }
+
+    @Override
+    public void deleteTopic(TopicEntity topicEntity) {
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setTopicName(topicEntity.getTopicName());
+        groupMemberEntity.setState("empty");
+        oprGroupMemberMapper.updateMemberByTopic(groupMemberEntity);
+        topicMapper.deleteTopic(topicEntity);
+    }
+}
diff --git a/eventmesh-dashboard-console/src/main/resources/application-dev.yml b/eventmesh-dashboard-console/src/main/resources/application-dev.yml
index 1c5e840..0ff18a1 100644
--- a/eventmesh-dashboard-console/src/main/resources/application-dev.yml
+++ b/eventmesh-dashboard-console/src/main/resources/application-dev.yml
@@ -32,7 +32,7 @@
       driver-class-name: com.mysql.cj.jdbc.Driver
       url: jdbc:mysql://localhost:3306/eventmesh-dashboard?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true
       username: root
-      password: root
+      password: 123456
 
       initial-size: 1
       max-active: 50
@@ -44,9 +44,12 @@
       test-while-idle: true
       min-evictable-idle-time-millis: 300000
 
+mybatis:
+  type-aliases-package: org.apache.eventmesh.dashboard.console.entity
+
 # cron job config, use cron expression
 cron:
-    #health check job
-    health: "0/15 * * * * ? *"
+  #health check job
+  health: "0/15 * * * * ? *"
 
 
diff --git a/eventmesh-dashboard-console/src/main/resources/eventmesh-dashboard.sql b/eventmesh-dashboard-console/src/main/resources/eventmesh-dashboard.sql
index 8de09e7..96cf1e3 100644
--- a/eventmesh-dashboard-console/src/main/resources/eventmesh-dashboard.sql
+++ b/eventmesh-dashboard-console/src/main/resources/eventmesh-dashboard.sql
@@ -14,28 +14,112 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+CREATE TABLE `group`
+(
+    `id`           bigint unsigned                                  NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`   bigint                                           NOT NULL DEFAULT '-1' COMMENT '集群id',
+    `name`         varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称',
+    `member_count` int unsigned                                     NOT NULL DEFAULT '0' COMMENT '成员数',
+    `members`      text COMMENT 'group的member列表',
+    `type`         tinyint                                          NOT NULL COMMENT 'group类型 0:consumer 1:producer',
+    `state`        varchar(64)                                      NOT NULL DEFAULT '' COMMENT '状态',
+    `create_time`  timestamp                                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`  timestamp                                        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `is_delete`    int                                              NOT NULL DEFAULT '0',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_id`, `name`),
+    KEY `cluster_id` (`cluster_id`, `name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 322
+  DEFAULT CHARSET = utf8mb3 COMMENT ='Group信息表'
+
+
+
+CREATE TABLE `group_member`
+(
+    `id`             bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`     bigint          NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `topic_name`     varchar(192)    NOT NULL DEFAULT '' COMMENT 'Topic名称',
+    `group_name`     varchar(192)    NOT NULL DEFAULT '' COMMENT 'Group名称',
+    `eventmesh_user` varchar(192)    NOT NULL DEFAULT '' COMMENT 'EventMesh用户',
+    `state`          varchar(64)     NOT NULL DEFAULT '' COMMENT '状态',
+    `create_time`    timestamp       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`    timestamp       NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `is_delete`      int             NOT NULL DEFAULT '0',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uniq_cluster_topic_group` (`cluster_id`, `topic_name`, `group_name`),
+    KEY `cluster_id` (`cluster_id`, `topic_name`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 257
+  DEFAULT CHARSET = utf8mb3 COMMENT ='GroupMember信息表'
+
+
+
+CREATE TABLE `operation_log`
+(
+    `id`             bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`     bigint          NOT NULL DEFAULT '-1' COMMENT '物理集群ID',
+    `operation_type` varchar(192)    NOT NULL DEFAULT '' COMMENT '操作类型,如:启动,停止,重启,添加,删除,修改',
+    `status`         int             NOT NULL DEFAULT '0' COMMENT '操作状态 0:未知,1:执行中,2:成功,3:失败',
+    `content`    text COMMENT '备注信息',
+    `create_time`    timestamp       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `end_time`       timestamp       NULL     DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
+    `operation_user` varchar(192)             DEFAULT NULL,
+    `result` text,
+    `target_type`    varchar(192)    NOT NULL,
+    `is_delete`      int             NOT NULL DEFAULT '0',
+    PRIMARY KEY (`id`),
+    KEY `idx_cluster_phy_id` (`cluster_id`),
+    KEY `idx_status` (`status`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 68
+  DEFAULT CHARSET = utf8mb3 COMMENT ='操作记录信息表'
+
+
+
+CREATE TABLE `topic`
+(
+    `id`           bigint unsigned                                  NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`   bigint                                           NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `topic_name`   varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称',
+    `runtime_id`   varchar(2048)                                    NOT NULL DEFAULT '' COMMENT 'RuntimeId',
+    `storage_id`   varchar(2048)                                    NOT NULL DEFAULT '' COMMENT 'StorageId',
+    `retention_ms` bigint                                           NOT NULL DEFAULT '-2' COMMENT '保存时间,-2:未知,-1:无限制,>=0对应时间,单位ms',
+    `type`         tinyint                                          NOT NULL DEFAULT '0' COMMENT 'Topic类型,默认0,0:普通,1:EventMesh内部',
+    `description`  text COMMENT '备注信息',
+    `create_time`  timestamp                                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(尽量与Topic实际创建时间一致)',
+    `update_time`  timestamp                                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间(尽量与Topic实际创建时间一致)',
+    `is_delete`    int                                              NOT NULL DEFAULT '0',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uniq_cluster_phy_id_topic_name` (`cluster_id`, `topic_name`),
+    KEY `cluster_id` (`cluster_id`, `topic_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 562
+  DEFAULT CHARSET = utf8mb3 COMMENT ='Topic信息表'
+
+
 
 DROP TABLE IF EXISTS `client`;
 CREATE TABLE `client`
 (
-    `id`             bigint(20)          NOT NULL AUTO_INCREMENT COMMENT 'id',
-    `cluster_id` bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
-    `name`           varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端名称',
-    `platform`       varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端平台',
-    `language`       varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端语言',
-    `pid`            bigint(22)          NOT NULL DEFAULT '-1' COMMENT '客户端进程ID',
-    `host`           varchar(128)        NOT NULL DEFAULT '' COMMENT '客户端地址',
-    `port`           int(16)             NOT NULL DEFAULT '-1' COMMENT '客户端端口',
-    `protocol`       varchar(192)        NOT NULL DEFAULT '' COMMENT '协议类型',
-    `status`         tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
-    `config_ids`     text                NOT NULL DEFAULT '' COMMENT 'csv config id list, like:1,3,7',
-    `description`    text                NOT NULL DEFAULT '' COMMENT '客户端描述',
-    `create_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `end_time`       timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
-    `update_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `id`          bigint(20)          NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`  bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `name`        varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端名称',
+    `platform`    varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端平台',
+    `language`    varchar(192)        NOT NULL DEFAULT '' COMMENT '客户端语言',
+    `pid`         bigint(22)          NOT NULL DEFAULT '-1' COMMENT '客户端进程ID',
+    `host`        varchar(128)        NOT NULL DEFAULT '' COMMENT '客户端地址',
+    `port`        int(16)             NOT NULL DEFAULT '-1' COMMENT '客户端端口',
+    `protocol`    varchar(192)        NOT NULL DEFAULT '' COMMENT '协议类型',
+    `status`      tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
+    `config_ids`  text                NOT NULL DEFAULT '' COMMENT 'csv config id list, like:1,3,7',
+    `description` text                NOT NULL DEFAULT '' COMMENT '客户端描述',
+    `create_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `end_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
+    `update_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
 
     PRIMARY KEY (`id`),
-    INDEX  `idx_cluster_id` (`cluster_id`)
+    INDEX `idx_cluster_id` (`cluster_id`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8 COMMENT ='客户端信息表';
 
@@ -44,16 +128,16 @@
 DROP TABLE IF EXISTS `connector`;
 CREATE TABLE `connector`
 (
-    `id`                 bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
-    `cluster_id`     bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
-    `name`               varchar(512)        NOT NULL DEFAULT '' COMMENT 'Connector名称',
-    `class_name`         varchar(512)        NOT NULL DEFAULT '' COMMENT 'Connector类',
-    `type`               varchar(32)         NOT NULL DEFAULT '' COMMENT 'Connector类型',
-    `status`             tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
-    `pod_state`          tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'k8s pod状态。0: pending;1: running;2: success;3: failed;4: unknown',
-    `config_ids`         text                NOT NULL DEFAULT '' COMMENT 'csv config id list, like:1,3,7',
-    `create_time`        timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `update_time`        timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `id`          bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`  bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `name`        varchar(512)        NOT NULL DEFAULT '' COMMENT 'Connector名称',
+    `class_name`  varchar(512)        NOT NULL DEFAULT '' COMMENT 'Connector类',
+    `type`        varchar(32)         NOT NULL DEFAULT '' COMMENT 'Connector类型',
+    `status`      tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
+    `pod_state`   tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'k8s pod状态。0: pending;1: running;2: success;3: failed;4: unknown',
+    `config_ids`  text                NOT NULL DEFAULT '' COMMENT 'csv config id list, like:1,3,7',
+    `create_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
     PRIMARY KEY (`id`),
     INDEX `idx_cluster_id` (`cluster_id`)
 ) ENGINE = InnoDB
@@ -62,20 +146,20 @@
 DROP TABLE IF EXISTS `connection`;
 CREATE TABLE `connection`
 (
-    `id`             bigint(20)          NOT NULL AUTO_INCREMENT COMMENT 'id',
-    `cluster_id` bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
-    `source_type`    varchar(64)         NOT NULL DEFAULT '' COMMENT 'source类型,可以为client或source connector',
-    `source_id`      bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'client或source connector ID',
-    `sink_type`      varchar(64)         NOT NULL DEFAULT '' COMMENT 'sink类型,可以为client或sink connector',
-    `sink_id`        bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'client或sink connector ID',
-    `runtime_id`     bigint(20)          NOT NULL DEFAULT '-1' COMMENT '对应runtime id',
-    `status`         tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
-    `topic`          varchar(192)        NOT NULL DEFAULT '' COMMENT 'topic name',
-    `group_id`       bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'GroupID',
-    `description`    text                NOT NULL DEFAULT '' COMMENT '客户端描述',
-    `create_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `end_time`       timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
-    `update_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `id`          bigint(20)          NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `cluster_id`  bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `source_type` varchar(64)         NOT NULL DEFAULT '' COMMENT 'source类型,可以为client或source connector',
+    `source_id`   bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'client或source connector ID',
+    `sink_type`   varchar(64)         NOT NULL DEFAULT '' COMMENT 'sink类型,可以为client或sink connector',
+    `sink_id`     bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'client或sink connector ID',
+    `runtime_id`  bigint(20)          NOT NULL DEFAULT '-1' COMMENT '对应runtime id',
+    `status`      tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
+    `topic`       varchar(192)        NOT NULL DEFAULT '' COMMENT 'topic name',
+    `group_id`    bigint(20)          NOT NULL DEFAULT '-1' COMMENT 'GroupID',
+    `description` text                NOT NULL DEFAULT '' COMMENT '客户端描述',
+    `create_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `end_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
+    `update_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
 
     PRIMARY KEY (`id`),
     INDEX `idx_cluster_id` (`cluster_id`),
@@ -89,14 +173,14 @@
 DROP TABLE IF EXISTS `health_check_result`;
 CREATE TABLE `health_check_result`
 (
-    `id`             bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
-    `dimension`      int(11)             NOT NULL DEFAULT '0' COMMENT '检查维度(0:未知,1:Cluster,2:Runtime,3:Topic,4:Group)',
-    `config_name`    varchar(192)        NOT NULL DEFAULT '' COMMENT '配置名',
-    `cluster_id` bigint(20)          NOT NULL DEFAULT '0' COMMENT '集群ID',
-    `res_name`       varchar(192)        NOT NULL DEFAULT '' COMMENT '资源名称',
-    `passed`         tinyint(4)          NOT NULL DEFAULT '0' COMMENT '检查通过(0:未通过,1:通过)',
-    `create_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `update_time`    timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    `id`          bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
+    `dimension`   int(11)             NOT NULL DEFAULT '0' COMMENT '检查维度(0:未知,1:Cluster,2:Runtime,3:Topic,4:Group)',
+    `config_name` varchar(192)        NOT NULL DEFAULT '' COMMENT '配置名',
+    `cluster_id`  bigint(20)          NOT NULL DEFAULT '0' COMMENT '集群ID',
+    `res_name`    varchar(192)        NOT NULL DEFAULT '' COMMENT '资源名称',
+    `passed`      tinyint(4)          NOT NULL DEFAULT '0' COMMENT '检查通过(0:未通过,1:通过)',
+    `create_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
     PRIMARY KEY (`id`),
     INDEX `idx_cluster_id` (`cluster_id`),
     UNIQUE KEY `uniq_dimension_config_cluster_res` (`dimension`, `config_name`, `cluster_id`, `res_name`)
@@ -106,20 +190,20 @@
 DROP TABLE IF EXISTS `meta`;
 CREATE TABLE `meta`
 (
-    `id`                   bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
-    `name`                 varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心名称',
-    `type`                 varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心类型,nacos,etcd,zookeeper',
-    `version`              varchar(128)        NOT NULL DEFAULT '' COMMENT '注册中心版本',
-    `cluster_id`       bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
-    `host`                 varchar(128)        NOT NULL DEFAULT '' COMMENT '注册中心地址',
-    `port`                 int(16)             NOT NULL DEFAULT '-1' COMMENT '注册中心端口',
-    `role`                 varchar(16)         NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer',
-    `username`             varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心用户名',
-    `params`               varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心启动参数',
-    `status`               tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
+    `id`          bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+    `name`        varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心名称',
+    `type`        varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心类型,nacos,etcd,zookeeper',
+    `version`     varchar(128)        NOT NULL DEFAULT '' COMMENT '注册中心版本',
+    `cluster_id`  bigint(20)          NOT NULL DEFAULT '-1' COMMENT '集群ID',
+    `host`        varchar(128)        NOT NULL DEFAULT '' COMMENT '注册中心地址',
+    `port`        int(16)             NOT NULL DEFAULT '-1' COMMENT '注册中心端口',
+    `role`        varchar(16)         NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer',
+    `username`    varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心用户名',
+    `params`      varchar(192)        NOT NULL DEFAULT '' COMMENT '注册中心启动参数',
+    `status`      tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态: 1启用,0未启用',
 
-    `create_time`          timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `update_time`          timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    `create_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
 
     PRIMARY KEY (`id`),
     INDEX `idx_cluster_id` (`cluster_id`)
diff --git a/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/linkage/log/TestOprLog.java b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/linkage/log/TestOprLog.java
new file mode 100644
index 0000000..afaf8d8
--- /dev/null
+++ b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/linkage/log/TestOprLog.java
@@ -0,0 +1,43 @@
+package org.apache.eventmesh.dashboard.console.linkage.log;
+
+import org.apache.eventmesh.dashboard.console.EventMeshDashboardApplication;
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.entity.log.LogEntity;
+import org.apache.eventmesh.dashboard.console.service.group.GroupService;
+import org.apache.eventmesh.dashboard.console.service.log.LogService;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EventMeshDashboardApplication.class)
+public class TestOprLog {
+
+    @Autowired
+    private GroupService groupService;
+
+    @Autowired
+    private LogService logService;
+
+    @Test
+    public void testGroupServiceOprLog() {
+        GroupEntity groupEntity = new GroupEntity(null, 1L, "logTest", 0, null, 1, "OK", null, null);
+        GroupEntity groupEntity1 = groupService.addGroup(groupEntity);
+        LogEntity logEntity = new LogEntity(null, 1L, "add", "Group", 2, groupEntity1.toString(), null, null, null, null);
+        logEntity.setResult(groupEntity.toString());
+        logEntity.setId(groupEntity1.getId());
+        List<LogEntity> logListByCluster = logService.getLogListByCluster(logEntity);
+        logListByCluster.get(0).setId(null);
+        logListByCluster.get(0).setCreateTime(null);
+        logListByCluster.get(0).setEndTime(null);
+        Assert.assertEquals(logListByCluster.get(0), logEntity);
+        Assert.assertEquals(logListByCluster.size(), 1);
+    }
+
+}
diff --git a/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/group/TestGroupMapper.java b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/group/TestGroupMapper.java
new file mode 100644
index 0000000..f247c3f
--- /dev/null
+++ b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/group/TestGroupMapper.java
@@ -0,0 +1,102 @@
+package org.apache.eventmesh.dashboard.console.unit.group;
+
+import org.apache.eventmesh.dashboard.console.EventMeshDashboardApplication;
+
+import org.apache.eventmesh.dashboard.console.entity.group.GroupEntity;
+import org.apache.eventmesh.dashboard.console.mapper.group.OprGroupMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EventMeshDashboardApplication.class)
+public class TestGroupMapper {
+
+    @Autowired
+    private OprGroupMapper groupMapper;
+
+    public List<GroupEntity> insertGroupData(String name) {
+        List<GroupEntity> groupEntities = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            GroupEntity groupEntity = new GroupEntity(null, (long) i, name, 0, null, 1, "OK", null, null);
+            groupMapper.addGroup(groupEntity);
+            groupEntities.add(groupEntity);
+        }
+        return groupEntities;
+    }
+
+    public List<GroupEntity> getRemovedTimeList(String name) {
+        GroupEntity groupEntity = new GroupEntity();
+        groupEntity.setName(name);
+        List<GroupEntity> groupEntities = groupMapper.selectGroup(groupEntity);
+        for (GroupEntity groupEntity1 : groupEntities) {
+            groupEntity1.setCreateTime(null);
+            groupEntity1.setUpdateTime(null);
+        }
+        return groupEntities;
+    }
+
+    @Test
+    public void testAddGroup() {
+        List<GroupEntity> groupEntities = this.insertGroupData("addGroup");
+        GroupEntity groupEntity = new GroupEntity();
+        groupEntity.setName("addGroup");
+        List<GroupEntity> groupEntities1 = groupMapper.selectGroup(groupEntity);
+        Assert.assertEquals(groupEntities, this.getRemovedTimeList("addGroup"));
+    }
+
+    @Test
+    public void testUpdateGroupById() {
+        List<GroupEntity> groupEntities = this.insertGroupData("updateById2");
+        GroupEntity groupEntity = groupEntities.get(9);
+        groupEntity.setType(3);
+        groupEntity.setMembers("1,");
+        groupEntity.setState("fail");
+        groupEntity.setMemberCount(1);
+        groupMapper.updateGroup(groupEntity);
+        Assert.assertEquals(groupEntities, this.getRemovedTimeList("updateById2"));
+    }
+
+    @Test
+    public void testDeleteGroupById() {
+        List<GroupEntity> groupEntities = this.insertGroupData("deleteById");
+        GroupEntity groupEntity = groupEntities.get(9);
+        groupMapper.deleteGroup(groupEntity);
+        groupEntities.remove(9);
+        Assert.assertEquals(groupEntities, this.getRemovedTimeList("deleteById"));
+    }
+
+    @Test
+    public void testSelectGroupById() {
+        List<GroupEntity> groupEntities = this.insertGroupData("selectById");
+        GroupEntity groupEntity = groupMapper.selectGroupById(groupEntities.get(0));
+        groupEntity.setCreateTime(null);
+        groupEntity.setUpdateTime(null);
+        Assert.assertEquals(groupEntities.get(0), groupEntity);
+    }
+
+    @Test
+    public void testSelectGroupByClusterId() {
+        List<GroupEntity> groupEntities = this.insertGroupData("selectByUnique");
+        GroupEntity groupEntity1 = new GroupEntity();
+        groupEntity1.setClusterId(groupEntities.get(0).getClusterId());
+        groupEntity1.setName(groupEntities.get(0).getName());
+        GroupEntity groupEntity = groupMapper.selectGroupByUnique(groupEntity1);
+        groupEntity.setCreateTime(null);
+        groupEntity.setUpdateTime(null);
+        Assert.assertEquals(groupEntities.get(0), groupEntity);
+    }
+
+    @Test
+    public void testSelectGroup() {
+        List<GroupEntity> groupEntities = this.insertGroupData("selectByDynamic1");
+        Assert.assertEquals(groupEntities, this.getRemovedTimeList("Dynamic1"));
+    }
+}
diff --git a/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/groupmember/testGroupMemberMapper.java b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/groupmember/testGroupMemberMapper.java
new file mode 100644
index 0000000..d3a20a0
--- /dev/null
+++ b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/groupmember/testGroupMemberMapper.java
@@ -0,0 +1,141 @@
+package org.apache.eventmesh.dashboard.console.unit.groupmember;
+
+import org.apache.eventmesh.dashboard.console.EventMeshDashboardApplication;
+import org.apache.eventmesh.dashboard.console.entity.groupmember.GroupMemberEntity;
+import org.apache.eventmesh.dashboard.console.mapper.groupmember.OprGroupMemberMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EventMeshDashboardApplication.class)
+public class testGroupMemberMapper {
+
+    @Autowired
+    OprGroupMemberMapper groupMemberMapper;
+
+    public List<GroupMemberEntity> insertGroupData(String topicName, String groupName) {
+        List<GroupMemberEntity> groupMemberEntities = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            GroupMemberEntity groupMemberEntity = new GroupMemberEntity(null, (long) i, topicName, groupName, "admin", "active", null, null);
+            groupMemberMapper.addGroupMember(groupMemberEntity);
+            groupMemberEntities.add(groupMemberEntity);
+        }
+        return groupMemberEntities;
+    }
+
+    public List<GroupMemberEntity> getRemovedTimeList(String topicName, String groupName) {
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setTopicName(topicName);
+        groupMemberEntity.setGroupName(groupName);
+        List<GroupMemberEntity> groupEntities = groupMemberMapper.selectMember(groupMemberEntity);
+        for (GroupMemberEntity groupEntity1 : groupEntities) {
+            groupEntity1.setCreateTime(null);
+            groupEntity1.setUpdateTime(null);
+        }
+        return groupEntities;
+    }
+
+    @Test
+    public void testAddGroupMember() {
+        List<GroupMemberEntity> add1 = this.insertGroupData("add1", "groupMember");
+        Assert.assertEquals(add1, this.getRemovedTimeList("add1", "groupMember"));
+    }
+
+    @Test
+    public void testGetGroupMemberByClusterId() {
+        List<GroupMemberEntity> add1 = this.insertGroupData("getByCluster", "groupMember");
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setClusterId(add1.get(1).getClusterId());
+        List<GroupMemberEntity> groupByClusterId = groupMemberMapper.getGroupByClusterId(groupMemberEntity);
+        GroupMemberEntity groupMemberEntity1 = groupByClusterId.get(0);
+        groupMemberEntity1.setCreateTime(null);
+        groupMemberEntity1.setUpdateTime(null);
+        Assert.assertEquals(1, groupByClusterId.size());
+        Assert.assertEquals(add1.get(1), groupMemberEntity1);
+    }
+
+    @Test
+    public void testDeleteGroupMemberById() {
+        List<GroupMemberEntity> add1 = this.insertGroupData("getById", "groupMember");
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setId(add1.get(2).getId());
+        GroupMemberEntity groupMemberEntity1 = groupMemberMapper.selectGroupMemberById(groupMemberEntity);
+        groupMemberEntity1.setUpdateTime(null);
+        groupMemberEntity1.setCreateTime(null);
+        Assert.assertEquals(groupMemberEntity1, add1.get(2));
+    }
+
+    @Test
+    public void testUpdateGroupMemberById() {
+        List<GroupMemberEntity> add1 = this.insertGroupData("updateById", "groupMember");
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        add1.get(1).setState("fail1");
+        groupMemberEntity.setState("fail1");
+        groupMemberEntity.setId(add1.get(1).getId());
+        groupMemberMapper.updateGroupMember(groupMemberEntity);
+        GroupMemberEntity groupMemberEntity1 = groupMemberMapper.selectGroupMemberById(add1.get(1));
+        groupMemberEntity1.setUpdateTime(null);
+        groupMemberEntity1.setCreateTime(null);
+        Assert.assertEquals(groupMemberEntity1, add1.get(1));
+    }
+
+    @Test
+    public void testSelectGroupMemberByUnique() {
+        List<GroupMemberEntity> groupMemberEntities = this.insertGroupData("selectByUnique", "groupMember");
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setClusterId(groupMemberEntities.get(1).getClusterId());
+        groupMemberEntity.setTopicName(groupMemberEntities.get(1).getTopicName());
+        groupMemberEntity.setGroupName(groupMemberEntities.get(1).getGroupName());
+        GroupMemberEntity groupMemberEntity1 = groupMemberMapper.selectGroupMemberByUnique(groupMemberEntity);
+        groupMemberEntity1.setUpdateTime(null);
+        groupMemberEntity1.setCreateTime(null);
+        Assert.assertEquals(groupMemberEntity1, groupMemberEntities.get(1));
+    }
+
+    @Test
+    public void testSelectGroupMemberByGroup() {
+        List<GroupMemberEntity> groupMemberEntities = this.insertGroupData("selectByGroup1", "groupMember1");
+        List<GroupMemberEntity> removedTimeList = this.getRemovedTimeList(null, "groupMember1");
+        Assert.assertEquals(groupMemberEntities, removedTimeList);
+    }
+
+    @Test
+    public void testSelectGroupMemberByTopic() {
+        List<GroupMemberEntity> groupMemberEntities = this.insertGroupData("selectByTopic1", "groupMember2");
+        List<GroupMemberEntity> removedTimeList = this.getRemovedTimeList("selectByTopic1", null);
+        Assert.assertEquals(groupMemberEntities, removedTimeList);
+    }
+
+    @Test
+    public void testUpdateGroupMemberByTopic() {
+        List<GroupMemberEntity> groupMemberEntities = this.insertGroupData("updateByTopic1", "groupMember2");
+        for (GroupMemberEntity groupMemberEntity : groupMemberEntities) {
+            groupMemberEntity.setState("fail2");
+        }
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setState("fail2");
+        groupMemberEntity.setTopicName("updateByTopic1");
+        groupMemberMapper.updateMemberByTopic(groupMemberEntity);
+        Assert.assertEquals(this.getRemovedTimeList("updateByTopic1", null), groupMemberEntities);
+    }
+
+    @Test
+    public void testSelectGroupMemberById() {
+        List<GroupMemberEntity> groupMemberEntities = this.insertGroupData("updateById1", "groupMember2");
+        GroupMemberEntity groupMemberEntity = new GroupMemberEntity();
+        groupMemberEntity.setId(groupMemberEntities.get(5).getId());
+        GroupMemberEntity groupMemberEntity1 = groupMemberMapper.selectGroupMemberById(groupMemberEntity);
+        groupMemberEntity1.setCreateTime(null);
+        groupMemberEntity1.setUpdateTime(null);
+        Assert.assertEquals(groupMemberEntity1, groupMemberEntities.get(5));
+    }
+
+}
diff --git a/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/topic/testTopicMapper.java b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/topic/testTopicMapper.java
new file mode 100644
index 0000000..7472792
--- /dev/null
+++ b/eventmesh-dashboard-console/src/test/java/org/apache/eventmesh/dashboard/console/unit/topic/testTopicMapper.java
@@ -0,0 +1,116 @@
+package org.apache.eventmesh.dashboard.console.unit.topic;
+
+import org.apache.eventmesh.dashboard.console.EventMeshDashboardApplication;
+import org.apache.eventmesh.dashboard.console.entity.topic.TopicEntity;
+import org.apache.eventmesh.dashboard.console.mapper.topic.TopicMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = EventMeshDashboardApplication.class)
+public class testTopicMapper {
+
+    @Autowired
+    private TopicMapper topicMapper;
+
+    public List<TopicEntity> insertGroupData(String topicName) {
+        List<TopicEntity> topicEntities = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            TopicEntity topicEntity = new TopicEntity(null, (long) i, topicName, "10", "10", 100L, 1, "testTopic", null, null);
+            topicMapper.addTopic(topicEntity);
+            topicEntities.add(topicEntity);
+        }
+        return topicEntities;
+    }
+
+    public List<TopicEntity> getRemovedTimeList(String topicName, Long clusterId) {
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setTopicName(topicName);
+        topicEntity.setClusterId(clusterId);
+        List<TopicEntity> topicEntities = topicMapper.getTopicList(topicEntity);
+        for (TopicEntity topic : topicEntities) {
+            topic.setCreateTime(null);
+            topic.setUpdateTime(null);
+        }
+        return topicEntities;
+    }
+
+    @Test
+    public void testSelectTopicByClusterId() {
+        List<TopicEntity> topicEntities = this.insertGroupData("SelectById111");
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setClusterId(topicEntities.get(9).getClusterId());
+        List<TopicEntity> topicEntity1 = topicMapper.getTopicList(topicEntity);
+        topicEntity1.get(0).setCreateTime(null);
+        topicEntity1.get(0).setUpdateTime(null);
+        Assert.assertEquals(topicEntity1.get(0), topicEntities.get(9));
+        Assert.assertEquals(1, topicEntity1.size());
+    }
+
+    @Test
+    public void testAddTopic() {
+        List<TopicEntity> topicEntities = this.insertGroupData("add111");
+        List<TopicEntity> add111 = this.getRemovedTimeList("add111", null);
+        Assert.assertEquals(add111, topicEntities);
+    }
+
+    @Test
+    public void testUpdateTopic() {
+        List<TopicEntity> topicEntities = this.insertGroupData("update2");
+        topicEntities.get(5).setDescription("updateTest1");
+        topicEntities.get(5).setType(-1);
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setDescription("updateTest1");
+        topicEntity.setType(-1);
+        topicEntity.setId(topicEntities.get(5).getId());
+        topicMapper.updateTopic(topicEntity);
+        TopicEntity topicEntity1 = topicMapper.selectTopicById(topicEntity);
+        topicEntity1.setUpdateTime(null);
+        topicEntity1.setCreateTime(null);
+        Assert.assertEquals(topicEntity1, topicEntities.get(5));
+    }
+
+    @Test
+    public void testDeleteTopic() {
+        List<TopicEntity> topicEntities = this.insertGroupData("update72");
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setId(topicEntities.get(5).getId());
+        topicEntity.setClusterId(topicEntities.get(5).getClusterId());
+        topicEntity.setTopicName("update72");
+        topicMapper.deleteTopic(topicEntity);
+        List<TopicEntity> topicEntity1 = topicMapper.getTopicList(topicEntity);
+        Assert.assertEquals(true, topicEntity1.isEmpty());
+    }
+
+    @Test
+    public void testSelectTopicByUnique() {
+        List<TopicEntity> topicEntities = this.insertGroupData("unique11");
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setTopicName("unique11");
+        topicEntity.setClusterId(topicEntities.get(1).getClusterId());
+        TopicEntity topicEntity1 = topicMapper.selectTopicByUnique(topicEntity);
+        topicEntity1.setUpdateTime(null);
+        topicEntity1.setCreateTime(null);
+        Assert.assertEquals(topicEntity1, topicEntities.get(1));
+    }
+
+    @Test
+    public void testSelectTopicById() {
+        List<TopicEntity> topicEntities = this.insertGroupData("id1");
+        TopicEntity topicEntity = new TopicEntity();
+        topicEntity.setId(topicEntities.get(2).getId());
+        TopicEntity topicEntity1 = topicMapper.selectTopicById(topicEntity);
+        topicEntity1.setCreateTime(null);
+        topicEntity1.setUpdateTime(null);
+        Assert.assertEquals(topicEntity1, topicEntities.get(2));
+    }
+
+}