You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/06/01 15:06:34 UTC

[skywalking] branch master updated: Support UI template management. (#4843)

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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new d094a0f  Support UI template management. (#4843)
d094a0f is described below

commit d094a0f7c0b4a2cf0de38735128b5c07181e30d2
Author: 吴晟 Wu Sheng <wu...@foxmail.com>
AuthorDate: Mon Jun 1 23:06:14 2020 +0800

    Support UI template management. (#4843)
---
 apm-dist-es7/src/main/assembly/binary-es7.xml      |   3 +-
 apm-dist/src/main/assembly/binary.xml              |   3 +-
 docs/en/setup/backend/dynamic-config.md            |   2 +-
 docs/en/setup/backend/endpoint-grouping-rules.md   |   2 +-
 oap-server/server-bootstrap/pom.xml                |   3 +-
 ...ame_grouping.yml => endpoint-name-grouping.yml} |   0
 .../main/resources/ui-initialized-templates.yml    |  34 +++++
 .../skywalking/oap/server/core/CoreModule.java     |  10 +-
 .../oap/server/core/CoreModuleProvider.java        |  79 ++++++-----
 .../oap/server/core/analysis/DownSampling.java     |   2 +-
 .../oap/server/core/analysis/Stream.java           |   6 +-
 .../core/analysis/StreamAnnotationListener.java    |  11 +-
 .../core/analysis/management/ManagementData.java}  |  16 +--
 ...Worker.java => ManagementPersistentWorker.java} |  26 ++--
 ...ocessor.java => ManagementStreamProcessor.java} |  40 +++---
 .../worker/NoneStreamPersistentWorker.java         |  11 +-
 ...mingProcessor.java => NoneStreamProcessor.java} |   6 +-
 .../group/EndpointNameGroupingRuleWatcher.java     |   2 +-
 .../core/management/ui/template/UITemplate.java    |  92 +++++++++++++
 .../ui/template/UITemplateInitializer.java         |  91 +++++++++++++
 .../ui/template/UITemplateManagementService.java   |  61 +++++++++
 .../core/profile/ProfileTaskMutationService.java   |  11 +-
 .../oap/server/core/profile/ProfileTaskRecord.java |   4 +-
 .../core/query/enumeration/TemplateType.java}      |  19 +--
 .../server/core/query/input/DashboardSetting.java  |  44 +++++++
 .../core/query/type/DashboardConfiguration.java    |  48 +++++++
 .../core/query/type/TemplateChangeStatus.java}     |  20 +--
 .../oap/server/core/source/DefaultScopeDefine.java |   1 +
 .../{INoneStreamDAO.java => IManagementDAO.java}   |  10 +-
 .../oap/server/core/storage/INoneStreamDAO.java    |   2 -
 .../oap/server/core/storage/StorageDAO.java        |   3 +
 .../oap/server/core/storage/StorageModule.java     |  34 ++---
 .../oap/server/core/storage/annotation/Column.java |   4 +
 .../UITemplateManagementDAO.java}                  |  19 ++-
 .../skywalking/oap/server/core/CoreModuleTest.java |   2 +-
 .../group/EndpointGroupingRuleReaderTest.java      |   2 +-
 .../ui/template/UITemplateInitializerTest.java     |  57 ++++++++
 .../management/ui/template/UITemplateTest.java     |  48 +++++++
 ...ame_grouping.yml => endpoint-name-grouping.yml} |   0
 .../ui-initialized-templates-conflict.yml          |  51 ++++++++
 .../test/resources/ui-initialized-templates.yml    |  51 ++++++++
 .../oap/query/graphql/GraphQLQueryProvider.java    |  71 +++++-----
 .../resolver/UIConfigurationManagement.java        |  71 ++++++++++
 .../src/main/resources/query-protocol              |   2 +-
 .../StorageModuleElasticsearchProvider.java        |  40 +++---
 .../{StorageEsDAO.java => ManagementEsDAO.java}    |  41 +++---
 .../plugin/elasticsearch/base/StorageEsDAO.java    |   7 +
 .../query/UITemplateManagementEsDAO.java           | 129 ++++++++++++++++++
 .../StorageModuleElasticsearch7Provider.java       |  60 +++++----
 .../plugin/elasticsearch7/dao/StorageEs7DAO.java   |   8 ++
 .../plugin/influxdb/InfluxStorageProvider.java     |  11 +-
 .../plugin/influxdb/base/InfluxStorageDAO.java     |   7 +
 .../plugin/influxdb/base/ManagementDAO.java        |  73 +++++++++++
 .../plugin/influxdb/query/MetadataQuery.java       |   6 +-
 .../query/UITemplateManagementDAOImpl.java         | 144 +++++++++++++++++++++
 .../storage/plugin/jdbc/h2/H2StorageProvider.java  |  13 +-
 .../plugin/jdbc/h2/dao/H2ManagementDAO.java        |  59 +++++++++
 .../storage/plugin/jdbc/h2/dao/H2StorageDAO.java   |   7 +
 .../jdbc/h2/dao/H2UITemplateManagementDAO.java     | 111 ++++++++++++++++
 .../plugin/jdbc/mysql/MySQLStorageProvider.java    |  13 +-
 .../plugin/jdbc/mysql/MySQLTableInstaller.java     |  25 ++--
 .../testing/module/ModuleProviderTesting.java      |   2 +-
 .../tool/profile/core/MockCoreModuleProvider.java  |  22 ++--
 .../core/mock/MockStreamAnnotationListener.java    |   6 +-
 .../e2e/UIConfigurationManagementClient.java       | 144 +++++++++++++++++++++
 .../e2e/dashboard/DashboardConfiguration.java      |  19 ++-
 .../DashboardConfigurationListWrapper.java         |  15 +--
 .../dashboard/DashboardConfigurationMatcher.java   |  25 ++--
 .../e2e/dashboard/DashboardConfigurations.java     |  16 +--
 .../dashboard/DashboardConfigurationsMatcher.java  |  47 +++++++
 .../skywalking/e2e/dashboard/DashboardSetting.java |  19 +--
 .../e2e/dashboard/TemplateChangeStatus.java        |  18 +--
 .../e2e/dashboard/TemplateChangeStatusWrapper.java |  15 +--
 .../skywalking/e2e/dashboard/TemplateType.java     |  19 +--
 .../e2e-data/src/main/resources/ui-addTemplate.gql |  29 +++--
 .../src/main/resources/ui-changeTemplate.gql       |  29 +++--
 .../src/main/resources/ui-disableTemplate.gql      |  25 ++--
 .../src/main/resources/ui-getTemplates.gql         |  28 ++--
 .../apache/skywalking/e2e/storage/StorageE2E.java  |  86 +++++++++++-
 .../storage/dashboardConfiguration-change.yml      |  20 +--
 .../storage/dashboardConfiguration-disable.yml     |  20 +--
 .../expected/storage/dashboardConfiguration.yml    |  20 +--
 82 files changed, 1975 insertions(+), 477 deletions(-)

diff --git a/apm-dist-es7/src/main/assembly/binary-es7.xml b/apm-dist-es7/src/main/assembly/binary-es7.xml
index d6be958..2a27119 100644
--- a/apm-dist-es7/src/main/assembly/binary-es7.xml
+++ b/apm-dist-es7/src/main/assembly/binary-es7.xml
@@ -50,7 +50,8 @@
                 <include>component-libraries.yml</include>
                 <include>gateways.yml</include>
                 <include>service-apdex-threshold.yml</include>
-                <include>endpoint_name_grouping.yml</include>
+                <include>endpoint-name-grouping.yml</include>
+                <include>ui-initialized-templates.yml</include>
                 <include>oal/core.oal</include>
                 <include>oal/java-agent.oal</include>
                 <include>oal/dotnet-agent.oal</include>
diff --git a/apm-dist/src/main/assembly/binary.xml b/apm-dist/src/main/assembly/binary.xml
index 1161c1c..00dc189 100644
--- a/apm-dist/src/main/assembly/binary.xml
+++ b/apm-dist/src/main/assembly/binary.xml
@@ -50,7 +50,8 @@
                 <include>component-libraries.yml</include>
                 <include>gateways.yml</include>
                 <include>service-apdex-threshold.yml</include>
-                <include>endpoint_name_grouping.yml</include>
+                <include>ui-initialized-templates.yml</include>
+                <include>endpoint-name-grouping.yml</include>
                 <include>oal/core.oal</include>
                 <include>oal/java-agent.oal</include>
                 <include>oal/dotnet-agent.oal</include>
diff --git a/docs/en/setup/backend/dynamic-config.md b/docs/en/setup/backend/dynamic-config.md
index b9ce01e..8f44193 100755
--- a/docs/en/setup/backend/dynamic-config.md
+++ b/docs/en/setup/backend/dynamic-config.md
@@ -10,7 +10,7 @@ Right now, SkyWalking supports following dynamic configurations.
 |receiver-trace.default.uninstrumentedGateways| The uninstrumented gateways, override `gateways.yml`. | same as [`gateways.yml`](uninstrumented-gateways.md#configuration-format) |
 |alarm.default.alarm-settings| The alarm settings, will override `alarm-settings.yml`. | same as [`alarm-settings.yml`](backend-alarm.md) |
 |core.default.apdexThreshold| The apdex threshold settings, will override `service-apdex-threshold.yml`. | same as [`service-apdex-threshold.yml`](apdex-threshold.md) |
-|core.default.endpoint-name-grouping| The endpoint name grouping setting, will override `endpoint_name_grouping.yml`. | same as [`endpoint_name_grouping.yml`](endpoint-grouping-rules.md) |
+|core.default.endpoint-name-grouping| The endpoint name grouping setting, will override `endpoint-name-grouping.yml`. | same as [`endpoint-name-grouping.yml`](endpoint-grouping-rules.md) |
 
 
 This feature depends on upstream service, so it is **DISABLED** by default.
diff --git a/docs/en/setup/backend/endpoint-grouping-rules.md b/docs/en/setup/backend/endpoint-grouping-rules.md
index e44e6df..dd623be 100644
--- a/docs/en/setup/backend/endpoint-grouping-rules.md
+++ b/docs/en/setup/backend/endpoint-grouping-rules.md
@@ -6,7 +6,7 @@ There are some special cases, especially when people use REST style URI, the app
 such as putting order id in the URI, like `/prod/ORDER123` and `/prod/ORDER123`. But logically, people expect they could
 have an endpoint name like `prod/{order-id}`. This is the feature of parameterized endpoint grouping designed for.
 
-Current, user could set up grouping rules through the static YAML file, named `endpoint_name_grouping.yml`,
+Current, user could set up grouping rules through the static YAML file, named `endpoint-name-grouping.yml`,
 or use [Dynamic Configuration](dynamic-config.md) to initial and update the endpoint grouping rule.
 
 ## Configuration Format
diff --git a/oap-server/server-bootstrap/pom.xml b/oap-server/server-bootstrap/pom.xml
index 20b25f8..c0d1f09 100644
--- a/oap-server/server-bootstrap/pom.xml
+++ b/oap-server/server-bootstrap/pom.xml
@@ -242,7 +242,8 @@
                         <exclude>component-libraries.yml</exclude>
                         <exclude>gateways.yml</exclude>
                         <exclude>service-apdex-threshold.yml</exclude>
-                        <exclude>endpoint_name_grouping.yml</exclude>
+                        <exclude>endpoint-name-grouping.yml</exclude>
+                        <exclude>ui-initialized-templates.yml</exclude>
                         <exclude>oal/core.oal</exclude>
                         <exclude>oal/java-agent.oal</exclude>
                         <exclude>oal/dotnet-agent.oal</exclude>
diff --git a/oap-server/server-bootstrap/src/main/resources/endpoint_name_grouping.yml b/oap-server/server-bootstrap/src/main/resources/endpoint-name-grouping.yml
similarity index 100%
rename from oap-server/server-bootstrap/src/main/resources/endpoint_name_grouping.yml
rename to oap-server/server-bootstrap/src/main/resources/endpoint-name-grouping.yml
diff --git a/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml
new file mode 100644
index 0000000..76585b4
--- /dev/null
+++ b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml
@@ -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.
+
+# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time.
+#
+# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file
+# could be added automatically.
+
+#templates:
+#  - name: "APM (Agent based)"
+#    # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT.
+#    # DASHBOARD type templates could have multiple definitions, by using different names.
+#    # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only.
+#    type: "DASHBOARD"
+#    # Configuration could be defined through UI, and use `export` to format in the standard JSON.
+#    configuration: |-
+#      JSON format exported from UI.
+#    # Activated as the DASHBOARD type, makes this templates added into the UI page automatically.
+#    # False means providing a basic template, user needs to add it manually.
+#    activated: true
+#    # True means wouldn't show up on the dashboard. Only keeps the definition in the storage.
+#    disabled: false
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
index dc74e59..e796aca 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
@@ -28,6 +28,7 @@ import org.apache.skywalking.oap.server.core.config.ConfigService;
 import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService;
 import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
 import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService;
 import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
 import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
 import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
@@ -46,8 +47,8 @@ import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
 import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
 import org.apache.skywalking.oap.server.core.source.SourceReceiver;
 import org.apache.skywalking.oap.server.core.storage.model.IModelManager;
-import org.apache.skywalking.oap.server.core.storage.model.ModelManipulator;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
+import org.apache.skywalking.oap.server.core.storage.model.ModelManipulator;
 import org.apache.skywalking.oap.server.core.worker.IWorkerInstanceGetter;
 import org.apache.skywalking.oap.server.core.worker.IWorkerInstanceSetter;
 import org.apache.skywalking.oap.server.library.module.ModuleDefine;
@@ -82,10 +83,15 @@ public class CoreModule extends ModuleDefine {
         addQueryService(classes);
         addProfileService(classes);
         addOALService(classes);
+        addManagementService(classes);
 
         classes.add(CommandService.class);
 
-        return classes.toArray(new Class[] {});
+        return classes.toArray(new Class[]{});
+    }
+
+    private void addManagementService(List<Class> classes) {
+        classes.add(UITemplateManagementService.class);
     }
 
     private void addProfileService(List<Class> classes) {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
index cd6430b..6aeba0f 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
@@ -28,6 +28,7 @@ import org.apache.skywalking.oap.server.core.analysis.DisableRegister;
 import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener;
 import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
 import org.apache.skywalking.oap.server.core.analysis.metrics.ApdexMetrics;
+import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor;
 import org.apache.skywalking.oap.server.core.annotation.AnnotationScan;
@@ -45,6 +46,8 @@ import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogServ
 import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping;
 import org.apache.skywalking.oap.server.core.config.group.EndpointNameGroupingRuleWatcher;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateInitializer;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService;
 import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
 import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
 import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
@@ -87,6 +90,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti
 import org.apache.skywalking.oap.server.library.server.ServerException;
 import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer;
 import org.apache.skywalking.oap.server.library.server.jetty.JettyServer;
+import org.apache.skywalking.oap.server.library.util.ResourceUtils;
 import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
 
 /**
@@ -139,14 +143,14 @@ public class CoreModuleProvider extends ModuleProvider {
         }
         EndpointNameGrouping endpointNameGrouping = new EndpointNameGrouping();
         this.registerServiceImplementation(NamingControl.class, new NamingControl(
-            moduleConfig.getServiceNameMaxLength(),
-            moduleConfig.getInstanceNameMaxLength(),
-            moduleConfig.getEndpointNameMaxLength(),
-            endpointNameGrouping
+                moduleConfig.getServiceNameMaxLength(),
+                moduleConfig.getInstanceNameMaxLength(),
+                moduleConfig.getEndpointNameMaxLength(),
+                endpointNameGrouping
         ));
         try {
             endpointNameGroupingRuleWatcher = new EndpointNameGroupingRuleWatcher(
-                this, endpointNameGrouping);
+                    this, endpointNameGrouping);
         } catch (FileNotFoundException e) {
             throw new ModuleStartException(e.getMessage(), e);
         }
@@ -174,8 +178,8 @@ public class CoreModuleProvider extends ModuleProvider {
 
         if (moduleConfig.isGRPCSslEnabled()) {
             grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(),
-                                        Paths.get(moduleConfig.getGRPCSslCertChainPath()).toFile(),
-                                        Paths.get(moduleConfig.getGRPCSslKeyPath()).toFile()
+                    Paths.get(moduleConfig.getGRPCSslCertChainPath()).toFile(),
+                    Paths.get(moduleConfig.getGRPCSslKeyPath()).toFile()
             );
         } else {
             grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort());
@@ -195,13 +199,13 @@ public class CoreModuleProvider extends ModuleProvider {
         grpcServer.initialize();
 
         jettyServer = new JettyServer(
-            moduleConfig.getRestHost(), moduleConfig.getRestPort(), moduleConfig.getRestContextPath(), moduleConfig
-            .getJettySelectors());
+                moduleConfig.getRestHost(), moduleConfig.getRestPort(), moduleConfig.getRestContextPath(), moduleConfig
+                .getJettySelectors());
         jettyServer.initialize();
 
         this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig));
         this.registerServiceImplementation(
-            DownSamplingConfigService.class, new DownSamplingConfigService(moduleConfig.getDownsampling()));
+                DownSamplingConfigService.class, new DownSamplingConfigService(moduleConfig.getDownsampling()));
 
         this.registerServiceImplementation(GRPCHandlerRegister.class, new GRPCHandlerRegisterImpl(grpcServer));
         this.registerServiceImplementation(JettyHandlerRegister.class, new JettyHandlerRegisterImpl(jettyServer));
@@ -220,7 +224,7 @@ public class CoreModuleProvider extends ModuleProvider {
         this.registerServiceImplementation(ModelManipulator.class, storageModels);
 
         this.registerServiceImplementation(
-            NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
+                NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
 
         this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager()));
         this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
@@ -234,9 +238,9 @@ public class CoreModuleProvider extends ModuleProvider {
 
         // add profile service implementations
         this.registerServiceImplementation(
-            ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager()));
+                ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager()));
         this.registerServiceImplementation(
-            ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig));
+                ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig));
         this.registerServiceImplementation(ProfileTaskCache.class, new ProfileTaskCache(getManager(), moduleConfig));
 
         this.registerServiceImplementation(CommandService.class, new CommandService(getManager()));
@@ -248,14 +252,17 @@ public class CoreModuleProvider extends ModuleProvider {
 
         if (moduleConfig.isGRPCSslEnabled()) {
             this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout(),
-                                                               Paths.get(moduleConfig.getGRPCSslTrustedCAPath())
-                                                                    .toFile()
+                    Paths.get(moduleConfig.getGRPCSslTrustedCAPath())
+                            .toFile()
             );
         } else {
             this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout());
         }
         this.registerServiceImplementation(RemoteClientManager.class, remoteClientManager);
 
+        // Management
+        this.registerServiceImplementation(UITemplateManagementService.class, new UITemplateManagementService(getManager()));
+
         MetricsStreamProcessor.getInstance().setEnableDatabaseSession(moduleConfig.isEnableDatabaseSession());
         TopNStreamProcessor.getInstance().setTopNWorkerReportCycle(moduleConfig.getTopNReportPeriod());
         apdexThresholdConfig = new ApdexThresholdConfig(this);
@@ -276,24 +283,24 @@ public class CoreModuleProvider extends ModuleProvider {
         }
 
         if (CoreModuleConfig.Role.Mixed.name()
-                                       .equalsIgnoreCase(
-                                           moduleConfig.getRole())
-            || CoreModuleConfig.Role.Aggregator.name()
-                                               .equalsIgnoreCase(
-                                                   moduleConfig.getRole())) {
+                .equalsIgnoreCase(
+                        moduleConfig.getRole())
+                || CoreModuleConfig.Role.Aggregator.name()
+                .equalsIgnoreCase(
+                        moduleConfig.getRole())) {
             RemoteInstance gRPCServerInstance = new RemoteInstance(
-                new Address(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), true));
+                    new Address(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), true));
             this.getManager()
-                .find(ClusterModule.NAME)
-                .provider()
-                .getService(ClusterRegister.class)
-                .registerRemote(gRPCServerInstance);
+                    .find(ClusterModule.NAME)
+                    .provider()
+                    .getService(ClusterRegister.class)
+                    .registerRemote(gRPCServerInstance);
         }
 
         DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME)
-                                                                              .provider()
-                                                                              .getService(
-                                                                                  DynamicConfigurationService.class);
+                .provider()
+                .getService(
+                        DynamicConfigurationService.class);
         dynamicConfigurationService.registerConfigChangeWatcher(apdexThresholdConfig);
         dynamicConfigurationService.registerConfigChangeWatcher(endpointNameGroupingRuleWatcher);
     }
@@ -314,13 +321,23 @@ public class CoreModuleProvider extends ModuleProvider {
         }
 
         CacheUpdateTimer.INSTANCE.start(getManager(), moduleConfig.getMetricsDataTTL());
+
+        try {
+            new UITemplateInitializer(ResourceUtils.read("ui-initialized-templates.yml"))
+                    .read()
+                    .forEach(uiTemplate -> {
+                        ManagementStreamProcessor.getInstance().in(uiTemplate);
+                    });
+        } catch (FileNotFoundException e) {
+            throw new ModuleStartException(e.getMessage(), e);
+        }
     }
 
     @Override
     public String[] requiredModules() {
-        return new String[] {
-            TelemetryModule.NAME,
-            ConfigurationModule.NAME
+        return new String[]{
+                TelemetryModule.NAME,
+                ConfigurationModule.NAME
         };
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java
index 98a4ece..93e0b74 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java
@@ -19,7 +19,7 @@ package org.apache.skywalking.oap.server.core.analysis;
 
 public enum DownSampling {
     /**
-     * None downsampling is for inventory
+     * None downsampling is for un-time-series data.
      */
     None(0, ""),
     /**
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java
index ea312d2..5de7086 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java
@@ -24,7 +24,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.Map;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
-import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor;
+import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
@@ -33,7 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
 /**
  * Stream annotation represents a metadata definition. Include the key values of the distributed streaming calculation.
  * See {@link MetricsStreamProcessor}, {@link RecordStreamProcessor}, {@link TopNStreamProcessor} and {@link
- * NoneStreamingProcessor} for more details.
+ * NoneStreamProcessor} for more details.
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
@@ -55,7 +55,7 @@ public @interface Stream {
 
     /**
      * @return the stream processor type, see {@link MetricsStreamProcessor}, {@link RecordStreamProcessor},  {@link
-     * TopNStreamProcessor} and {@link NoneStreamingProcessor} for more details.
+     * TopNStreamProcessor} and {@link NoneStreamProcessor} for more details.
      */
     Class<? extends StreamProcessor> processor();
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java
index 4c75c78..052ea50 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java
@@ -20,8 +20,9 @@ package org.apache.skywalking.oap.server.core.analysis;
 
 import java.lang.annotation.Annotation;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
+import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
-import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor;
+import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor;
 import org.apache.skywalking.oap.server.core.annotation.AnnotationListener;
@@ -56,14 +57,16 @@ public class StreamAnnotationListener implements AnnotationListener {
                 MetricsStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
             } else if (stream.processor().equals(TopNStreamProcessor.class)) {
                 TopNStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
-            } else if (stream.processor().equals(NoneStreamingProcessor.class)) {
-                NoneStreamingProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
+            } else if (stream.processor().equals(NoneStreamProcessor.class)) {
+                NoneStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
+            } else if (stream.processor().equals(ManagementStreamProcessor.class)) {
+                ManagementStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
             } else {
                 throw new UnexpectedException("Unknown stream processor.");
             }
         } else {
             throw new UnexpectedException(
-                "Stream annotation listener could only parse the class present stream annotation.");
+                    "Stream annotation listener could only parse the class present stream annotation.");
         }
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java
index c0756b4..9e35b8a 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java
@@ -16,16 +16,12 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.core.analysis.management;
 
-import org.junit.Assert;
-import org.junit.Test;
+import org.apache.skywalking.oap.server.core.storage.StorageData;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
-    }
+/**
+ * ManagementData provides the basic CRUD operations.
+ */
+public abstract class ManagementData implements StorageData {
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java
similarity index 63%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java
index 59c729c..8e41381 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java
@@ -19,36 +19,30 @@
 package org.apache.skywalking.oap.server.core.analysis.worker;
 
 import java.io.IOException;
-import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
-import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.worker.AbstractWorker;
 import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * None persistent use {@link INoneStreamDAO#insert(Model, NoneStream)} on get new data
- */
-public class NoneStreamPersistentWorker extends AbstractWorker<NoneStream> {
-
-    private static final Logger logger = LoggerFactory.getLogger(NoneStreamPersistentWorker.class);
 
+@Slf4j
+public class ManagementPersistentWorker extends AbstractWorker<ManagementData> {
     private final Model model;
-    private final INoneStreamDAO configDAO;
+    private final IManagementDAO configDAO;
 
-    public NoneStreamPersistentWorker(ModuleDefineHolder moduleDefineHolder, Model model, INoneStreamDAO configDAO) {
+    public ManagementPersistentWorker(ModuleDefineHolder moduleDefineHolder, Model model, IManagementDAO configDAO) {
         super(moduleDefineHolder);
         this.model = model;
         this.configDAO = configDAO;
     }
 
     @Override
-    public void in(NoneStream noneStream) {
+    public void in(ManagementData managementData) {
         try {
-            configDAO.insert(model, noneStream);
+            configDAO.insert(model, managementData);
         } catch (IOException e) {
-            logger.error(e.getMessage(), e);
+            log.error(e.getMessage(), e);
         }
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
similarity index 64%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
index cda63c2..8a44a4d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
@@ -26,57 +26,57 @@ import org.apache.skywalking.oap.server.core.analysis.DisableRegister;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
 import org.apache.skywalking.oap.server.core.analysis.Stream;
 import org.apache.skywalking.oap.server.core.analysis.StreamProcessor;
-import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
-import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.annotation.Storage;
-import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
 
 /**
- * none streaming is designed for user operation configuration in UI interface. It uses storage (synchronization)
- * similar to Inventory and supports TTL deletion mode similar to the record.
+ * ManagementProcessor represents the UI/CLI interactive process. They are management data, which size is not huge and
+ * time serious.
+ *
+ * @since 8.0.0
  */
-public class NoneStreamingProcessor implements StreamProcessor<NoneStream> {
-
-    private static final NoneStreamingProcessor PROCESSOR = new NoneStreamingProcessor();
-
-    private Map<Class<? extends NoneStream>, NoneStreamPersistentWorker> workers = new HashMap<>();
+public class ManagementStreamProcessor implements StreamProcessor<ManagementData> {
+    private static final ManagementStreamProcessor PROCESSOR = new ManagementStreamProcessor();
+    private Map<Class<? extends ManagementData>, ManagementPersistentWorker> workers = new HashMap<>();
 
-    public static NoneStreamingProcessor getInstance() {
+    public static ManagementStreamProcessor getInstance() {
         return PROCESSOR;
     }
 
     @Override
-    public void in(NoneStream noneStream) {
-        final NoneStreamPersistentWorker worker = workers.get(noneStream.getClass());
+    public void in(final ManagementData managementData) {
+        final ManagementPersistentWorker worker = workers.get(managementData.getClass());
         if (worker != null) {
-            worker.in(noneStream);
+            worker.in(managementData);
         }
     }
 
     @Override
-    public void create(ModuleDefineHolder moduleDefineHolder, Stream stream, Class<? extends NoneStream> streamClass) throws StorageException {
+    public void create(final ModuleDefineHolder moduleDefineHolder, final Stream stream, final Class<? extends ManagementData> streamClass) throws StorageException {
         if (DisableRegister.INSTANCE.include(stream.name())) {
             return;
         }
 
         StorageDAO storageDAO = moduleDefineHolder.find(StorageModule.NAME).provider().getService(StorageDAO.class);
-        INoneStreamDAO noneStream;
+        IManagementDAO managementDAO;
         try {
-            noneStream = storageDAO.newNoneStreamDao(stream.builder().newInstance());
+            managementDAO = storageDAO.newManagementDao(stream.builder().newInstance());
         } catch (InstantiationException | IllegalAccessException e) {
             throw new UnexpectedException("Create " + stream.builder()
-                                                            .getSimpleName() + " none stream record DAO failure.", e);
+                    .getSimpleName() + " none stream record DAO failure.", e);
         }
 
         ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class);
-        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), DownSampling.Second), true);
+        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), DownSampling.None), false);
 
-        final NoneStreamPersistentWorker persistentWorker = new NoneStreamPersistentWorker(moduleDefineHolder, model, noneStream);
+        final ManagementPersistentWorker persistentWorker = new ManagementPersistentWorker(moduleDefineHolder, model, managementDAO);
         workers.put(streamClass, persistentWorker);
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java
index 59c729c..865d38a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java
@@ -19,21 +19,18 @@
 package org.apache.skywalking.oap.server.core.analysis.worker;
 
 import java.io.IOException;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.worker.AbstractWorker;
 import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
- * None persistent use {@link INoneStreamDAO#insert(Model, NoneStream)} on get new data
+ * None persistent use {@link INoneStreamDAO#insert(Model, NoneStream)} on saving new data
  */
+@Slf4j
 public class NoneStreamPersistentWorker extends AbstractWorker<NoneStream> {
-
-    private static final Logger logger = LoggerFactory.getLogger(NoneStreamPersistentWorker.class);
-
     private final Model model;
     private final INoneStreamDAO configDAO;
 
@@ -48,7 +45,7 @@ public class NoneStreamPersistentWorker extends AbstractWorker<NoneStream> {
         try {
             configDAO.insert(model, noneStream);
         } catch (IOException e) {
-            logger.error(e.getMessage(), e);
+            log.error(e.getMessage(), e);
         }
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
similarity index 94%
rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java
rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
index cda63c2..8878d44 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
@@ -40,13 +40,13 @@ import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
  * none streaming is designed for user operation configuration in UI interface. It uses storage (synchronization)
  * similar to Inventory and supports TTL deletion mode similar to the record.
  */
-public class NoneStreamingProcessor implements StreamProcessor<NoneStream> {
+public class NoneStreamProcessor implements StreamProcessor<NoneStream> {
 
-    private static final NoneStreamingProcessor PROCESSOR = new NoneStreamingProcessor();
+    private static final NoneStreamProcessor PROCESSOR = new NoneStreamProcessor();
 
     private Map<Class<? extends NoneStream>, NoneStreamPersistentWorker> workers = new HashMap<>();
 
-    public static NoneStreamingProcessor getInstance() {
+    public static NoneStreamProcessor getInstance() {
         return PROCESSOR;
     }
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java
index 19b27ee..cfb307f 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java
@@ -40,7 +40,7 @@ public class EndpointNameGroupingRuleWatcher extends ConfigChangeWatcher {
         // This is just a place holder text representing the original text.
         ruleSetting = "SkyWalking endpoint rule";
         grouping.setEndpointGroupingRule(new EndpointGroupingRuleReader(
-            ResourceUtils.read("endpoint_name_grouping.yml")).read());
+            ResourceUtils.read("endpoint-name-grouping.yml")).read());
     }
 
     @Override
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java
new file mode 100644
index 0000000..376dedc
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.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.skywalking.oap.server.core.management.ui.template;
+
+import java.util.HashMap;
+import java.util.Map;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.Stream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
+import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.UI_TEMPLATE;
+
+@Setter
+@Getter
+@ScopeDeclaration(id = UI_TEMPLATE, name = "UITemplate")
+@Stream(name = UITemplate.INDEX_NAME, scopeId = UI_TEMPLATE, builder = UITemplate.Builder.class, processor = ManagementStreamProcessor.class)
+@EqualsAndHashCode(of = {
+        "name"
+}, callSuper = false)
+public class UITemplate extends ManagementData {
+    public static final String INDEX_NAME = "ui_template";
+    public static final String NAME = "name";
+    public static final String TYPE = "type";
+    public static final String CONFIGURATION = "configuration";
+    public static final String ACTIVATED = "activated";
+    public static final String DISABLED = "disabled";
+
+    @Column(columnName = NAME)
+    private String name;
+    @Column(columnName = TYPE, storageOnly = true)
+    private String type;
+    /**
+     * Configuration in JSON format.
+     */
+    @Column(columnName = CONFIGURATION, storageOnly = true, length = 1_000_000)
+    private String configuration;
+    @Column(columnName = ACTIVATED, storageOnly = true)
+    private int activated;
+    @Column(columnName = DISABLED)
+    private int disabled;
+
+    @Override
+    public String id() {
+        return name;
+    }
+
+    public static class Builder implements StorageBuilder<UITemplate> {
+        @Override
+        public UITemplate map2Data(final Map<String, Object> dbMap) {
+            UITemplate uiTemplate = new UITemplate();
+            uiTemplate.setName((String) dbMap.get(NAME));
+            uiTemplate.setType((String) dbMap.get(TYPE));
+            uiTemplate.setConfiguration((String) dbMap.get(CONFIGURATION));
+            uiTemplate.setActivated(((Number) dbMap.get(ACTIVATED)).intValue());
+            uiTemplate.setDisabled(((Number) dbMap.get(DISABLED)).intValue());
+            return uiTemplate;
+        }
+
+        @Override
+        public Map<String, Object> data2Map(final UITemplate storageData) {
+            final HashMap<String, Object> map = new HashMap<>();
+            map.put(NAME, storageData.getName());
+            map.put(TYPE, storageData.getType());
+            map.put(CONFIGURATION, storageData.getConfiguration());
+            map.put(ACTIVATED, storageData.getActivated());
+            map.put(DISABLED, storageData.getDisabled());
+            return map;
+        }
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java
new file mode 100644
index 0000000..4ec82ae
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.management.ui.template;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * UITemplateInitializer load the template from the config file in YAML format. The template definition is by JSON format in default,
+ * but it depends on the UI implementation only.
+ */
+public class UITemplateInitializer {
+    private Map yamlData;
+
+    public UITemplateInitializer(InputStream inputStream) {
+        Yaml yaml = new Yaml();
+        yamlData = yaml.loadAs(inputStream, Map.class);
+    }
+
+    public UITemplateInitializer(Reader io) {
+        Yaml yaml = new Yaml();
+        yamlData = yaml.loadAs(io, Map.class);
+    }
+
+    public List<UITemplate> read() {
+        List<UITemplate> uiTemplates = new ArrayList<>();
+        if (Objects.nonNull(yamlData)) {
+            List templates = (List) yamlData.get("templates");
+            if (templates != null) {
+                templates.forEach(templateObj -> {
+                    final Map template = (Map) templateObj;
+                    UITemplate newTemplate = new UITemplate();
+                    final String name = (String) template.get("name");
+                    if (StringUtil.isEmpty(name)) {
+                        throw new IllegalArgumentException("template name shouldn't be null");
+                    }
+                    newTemplate.setName(name);
+                    final String type = (String) template.getOrDefault("type", TemplateType.DASHBOARD.name());
+                    TemplateType.forName(type); // for checking.
+                    newTemplate.setType(type);
+                    final String configuration = (String) template.get("configuration");
+                    if (StringUtil.isEmpty(configuration)) {
+                        throw new IllegalArgumentException("template configuration shouldn't be null");
+                    }
+                    newTemplate.setConfiguration(configuration);
+                    newTemplate.setActivated(
+                            BooleanUtils.booleanToValue(
+                                    // The template should be activated in default, it is just an option.
+                                    (Boolean) template.getOrDefault("activated", false)
+                            )
+                    );
+                    newTemplate.setDisabled(
+                            BooleanUtils.booleanToValue(
+                                    // The template should be available in default.
+                                    (Boolean) template.getOrDefault("disabled", false)
+                            )
+                    );
+                    if (uiTemplates.contains(newTemplate)) {
+                        throw new IllegalArgumentException("Template " + newTemplate.getName() + " name conflicts");
+                    }
+                    uiTemplates.add(newTemplate);
+                });
+            }
+        }
+        return uiTemplates;
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java
new file mode 100644
index 0000000..63e4620
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.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.skywalking.oap.server.core.management.ui.template;
+
+import java.io.IOException;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.core.storage.StorageModule;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.module.Service;
+
+@RequiredArgsConstructor
+public class UITemplateManagementService implements Service {
+    private final ModuleManager moduleManager;
+    private UITemplateManagementDAO uiTemplateManagementDAO;
+
+    private UITemplateManagementDAO getUITemplateManagementDAO() {
+        if (uiTemplateManagementDAO == null) {
+            this.uiTemplateManagementDAO = moduleManager.find(StorageModule.NAME)
+                    .provider()
+                    .getService(UITemplateManagementDAO.class);
+        }
+        return uiTemplateManagementDAO;
+    }
+
+    public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) throws IOException {
+        return getUITemplateManagementDAO().getAllTemplates(includingDisabled);
+    }
+
+    public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException {
+        return getUITemplateManagementDAO().addTemplate(setting);
+    }
+
+    public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException {
+        return getUITemplateManagementDAO().changeTemplate(setting);
+    }
+
+    public TemplateChangeStatus disableTemplate(String name) throws IOException {
+        return getUITemplateManagementDAO().disableTemplate(name);
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java
index 202d4c7..b2601ab 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java
@@ -21,11 +21,12 @@ package org.apache.skywalking.oap.server.core.profile;
 import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.apm.network.constants.ProfileConstants;
 import org.apache.skywalking.apm.util.StringUtil;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
-import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor;
+import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTaskCreationResult;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
@@ -34,15 +35,11 @@ import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.module.Service;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 
+@RequiredArgsConstructor
 public class ProfileTaskMutationService implements Service {
-
     private final ModuleManager moduleManager;
     private IProfileTaskQueryDAO profileTaskQueryDAO;
 
-    public ProfileTaskMutationService(ModuleManager moduleManager) {
-        this.moduleManager = moduleManager;
-    }
-
     private IProfileTaskQueryDAO getProfileTaskDAO() {
         if (profileTaskQueryDAO == null) {
             this.profileTaskQueryDAO = moduleManager.find(StorageModule.NAME)
@@ -97,7 +94,7 @@ public class ProfileTaskMutationService implements Service {
         task.setCreateTime(createTime);
         task.setMaxSamplingCount(maxSamplingCount);
         task.setTimeBucket(TimeBucket.getRecordTimeBucket(taskEndTime));
-        NoneStreamingProcessor.getInstance().in(task);
+        NoneStreamProcessor.getInstance().in(task);
 
         return ProfileTaskCreationResult.builder().id(task.id()).build();
     }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java
index 6ec2fff..816c677 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java
@@ -25,7 +25,7 @@ import lombok.Setter;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.Stream;
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
-import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor;
+import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
 import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
@@ -38,7 +38,7 @@ import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.PR
 @Getter
 @Setter
 @ScopeDeclaration(id = PROFILE_TASK, name = "ProfileTask")
-@Stream(name = ProfileTaskRecord.INDEX_NAME, scopeId = PROFILE_TASK, builder = ProfileTaskRecord.Builder.class, processor = NoneStreamingProcessor.class)
+@Stream(name = ProfileTaskRecord.INDEX_NAME, scopeId = PROFILE_TASK, builder = ProfileTaskRecord.Builder.class, processor = NoneStreamProcessor.class)
 public class ProfileTaskRecord extends NoneStream {
 
     public static final String INDEX_NAME = "profile_task";
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java
similarity index 68%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java
index c0756b4..2d21c13 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java
@@ -16,16 +16,17 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.core.query.enumeration;
 
-import org.junit.Assert;
-import org.junit.Test;
+public enum TemplateType {
+    DASHBOARD,
+    TOPOLOGY_SERVICE,
+    TOPOLOGY_INSTANCE,
+    TOPOLOGY_ENDPOINT,
+    TOPOLOGY_SERVICE_RELATION,
+    TOPOLOGY_SERVICE_INSTANCE_RELATION;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
+    public static TemplateType forName(String name) {
+        return Enum.valueOf(TemplateType.class, name.toUpperCase());
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java
new file mode 100644
index 0000000..f9464d8
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.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.skywalking.oap.server.core.query.input;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
+import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+
+@Setter
+@Getter
+public class DashboardSetting {
+    private String name;
+    private TemplateType type;
+    private String configuration;
+    private boolean active;
+
+    public UITemplate toEntity() {
+        UITemplate uiTemplate = new UITemplate();
+        uiTemplate.setName(this.getName());
+        uiTemplate.setConfiguration(this.getConfiguration());
+        uiTemplate.setType(this.getType().name());
+        uiTemplate.setActivated(BooleanUtils.booleanToValue(this.isActive()));
+        uiTemplate.setDisabled(BooleanUtils.FALSE);
+        return uiTemplate;
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java
new file mode 100644
index 0000000..e4e2788
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.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.skywalking.oap.server.core.query.type;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
+import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+
+@Setter
+@Getter
+public class DashboardConfiguration {
+    private String name;
+    private TemplateType type;
+    /**
+     * Configuration in JSON format.
+     */
+    private String configuration;
+    private boolean activated;
+    private boolean disabled;
+
+    public DashboardConfiguration fromEntity(UITemplate templateEntity) {
+        this.setName(templateEntity.getName());
+        this.setType(TemplateType.forName(templateEntity.getType()));
+        this.setConfiguration(templateEntity.getConfiguration());
+        this.setActivated(BooleanUtils.valueToBoolean(templateEntity.getActivated()));
+        this.setDisabled(BooleanUtils.valueToBoolean(templateEntity.getDisabled()));
+
+        return this;
+    }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java
index c0756b4..8282672 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java
@@ -16,16 +16,16 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.core.query.type;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
-    }
+@Setter
+@Getter
+@Builder
+public class TemplateChangeStatus {
+    private boolean status;
+    private String message;
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
index 499d51f..4883446 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
@@ -66,6 +66,7 @@ public class DefaultScopeDefine {
     public static final int SERVICE_META = 29;
     public static final int SERVICE_INSTANCE_UPDATE = 30;
     public static final int NETWORK_ADDRESS_ALIAS = 31;
+    public static final int UI_TEMPLATE = 32;
 
     /**
      * Catalog of scope, the metrics processor could use this to group all generated metrics by oal rt.
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java
similarity index 79%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java
index 64d4da0..98c912e 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java
@@ -19,14 +19,12 @@
 package org.apache.skywalking.oap.server.core.storage;
 
 import java.io.IOException;
-import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 
 /**
- * Use synchronize storage to insert none stream data
+ * Use synchronize storage to insert storage data
  */
-public interface INoneStreamDAO extends DAO {
-
-    void insert(Model model, NoneStream noneStream) throws IOException;
-
+public interface IManagementDAO extends DAO {
+    void insert(Model model, ManagementData storageData) throws IOException;
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
index 64d4da0..685ef7c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
@@ -26,7 +26,5 @@ import org.apache.skywalking.oap.server.core.storage.model.Model;
  * Use synchronize storage to insert none stream data
  */
 public interface INoneStreamDAO extends DAO {
-
     void insert(Model model, NoneStream noneStream) throws IOException;
-
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java
index 7ee4dfc..8f5c722 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.server.core.storage;
 
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.library.module.Service;
@@ -33,4 +34,6 @@ public interface StorageDAO extends Service {
     IRecordDAO newRecordDao(StorageBuilder<Record> storageBuilder);
 
     INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder);
+
+    IManagementDAO newManagementDao(StorageBuilder<ManagementData> storageBuilder);
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
index 39dff1f..1b5b9cd 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.server.core.storage;
 
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
@@ -46,22 +47,23 @@ public class StorageModule extends ModuleDefine {
 
     @Override
     public Class[] services() {
-        return new Class[] {
-            IBatchDAO.class,
-            StorageDAO.class,
-            IHistoryDeleteDAO.class,
-            INetworkAddressAliasDAO.class,
-            ITopologyQueryDAO.class,
-            IMetricsQueryDAO.class,
-            ITraceQueryDAO.class,
-            IMetadataQueryDAO.class,
-            IAggregationQueryDAO.class,
-            IAlarmQueryDAO.class,
-            ITopNRecordsQueryDAO.class,
-            ILogQueryDAO.class,
-            IProfileTaskQueryDAO.class,
-            IProfileTaskLogQueryDAO.class,
-            IProfileThreadSnapshotQueryDAO.class
+        return new Class[]{
+                IBatchDAO.class,
+                StorageDAO.class,
+                IHistoryDeleteDAO.class,
+                INetworkAddressAliasDAO.class,
+                ITopologyQueryDAO.class,
+                IMetricsQueryDAO.class,
+                ITraceQueryDAO.class,
+                IMetadataQueryDAO.class,
+                IAggregationQueryDAO.class,
+                IAlarmQueryDAO.class,
+                ITopNRecordsQueryDAO.class,
+                ILogQueryDAO.class,
+                IProfileTaskQueryDAO.class,
+                IProfileTaskLogQueryDAO.class,
+                IProfileThreadSnapshotQueryDAO.class,
+                UITemplateManagementDAO.class
         };
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
index 83c6e52..370e132 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
@@ -61,6 +61,10 @@ public @interface Column {
     /**
      * @return the length of this column, this is only for {@link String} column. The usage of this depends on the
      * storage implementation.
+     *
+     * Notice, different lengths may cause different types.
+     * Such as, over 16383 would make the type in MySQL to be MEDIUMTEXT, due to database varchar max=16383
+     *
      * @since 7.1.0
      */
     int length() default 200;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java
similarity index 51%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java
index 64d4da0..aee1bbb 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java
@@ -16,17 +16,24 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.storage;
+package org.apache.skywalking.oap.server.core.storage.management;
 
 import java.io.IOException;
-import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
+import java.util.List;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.core.storage.DAO;
 
 /**
- * Use synchronize storage to insert none stream data
+ * UI Template management, including CRUD.
  */
-public interface INoneStreamDAO extends DAO {
+public interface UITemplateManagementDAO extends DAO {
+    List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) throws IOException;
 
-    void insert(Model model, NoneStream noneStream) throws IOException;
+    TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException;
 
+    TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException;
+
+    TemplateChangeStatus disableTemplate(String name) throws IOException;
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
index c0756b4..ba3facc 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
@@ -26,6 +26,6 @@ public class CoreModuleTest {
     public void testOpenServiceList() {
         CoreModule coreModule = new CoreModule();
 
-        Assert.assertEquals(30, coreModule.services().length);
+        Assert.assertEquals(31, coreModule.services().length);
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java
index 93b4825..e1e199b 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java
@@ -28,7 +28,7 @@ public class EndpointGroupingRuleReaderTest {
         EndpointGroupingRuleReader reader = new EndpointGroupingRuleReader(this.getClass()
                                                                                .getClassLoader()
                                                                                .getResourceAsStream(
-                                                                                   "endpoint_name_grouping.yml"));
+                                                                                   "endpoint-name-grouping.yml"));
         final EndpointGroupingRule rule = reader.read();
 
         StringFormatGroup.FormatResult formatResult = rule.format("serviceA", "/prod/123");
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java
new file mode 100644
index 0000000..2193285
--- /dev/null
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.management.ui.template;
+
+import java.util.List;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UITemplateInitializerTest {
+    @Test
+    public void testReadFile() {
+        UITemplateInitializer initializer = new UITemplateInitializer(this.getClass()
+                .getClassLoader()
+                .getResourceAsStream(
+                        "ui-initialized-templates.yml"));
+        final List<UITemplate> uiTemplates = initializer.read();
+
+        Assert.assertEquals(2, uiTemplates.size());
+        UITemplate uiTemplate = uiTemplates.get(0);
+        Assert.assertEquals("APM (Agent based)", uiTemplate.getName());
+        Assert.assertTrue(uiTemplate.getConfiguration().length() > 0);
+        Assert.assertEquals(BooleanUtils.TRUE, uiTemplate.getActivated());
+        Assert.assertEquals(BooleanUtils.FALSE, uiTemplate.getDisabled());
+
+        uiTemplate = uiTemplates.get(1);
+        Assert.assertEquals("APM (Service Mesh)", uiTemplate.getName());
+        Assert.assertTrue(uiTemplate.getConfiguration().length() > 0);
+        Assert.assertEquals(BooleanUtils.FALSE, uiTemplate.getActivated());
+        Assert.assertEquals(BooleanUtils.TRUE, uiTemplate.getDisabled());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTemplateConflict() {
+        UITemplateInitializer initializer = new UITemplateInitializer(this.getClass()
+                .getClassLoader()
+                .getResourceAsStream(
+                        "ui-initialized-templates-conflict.yml"));
+        final List<UITemplate> uiTemplates = initializer.read();
+    }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java
new file mode 100644
index 0000000..da25400
--- /dev/null
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.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.skywalking.oap.server.core.management.ui.template;
+
+import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UITemplateTest {
+    @Test
+    public void testSerialization() {
+        UITemplate uiTemplate = new UITemplate();
+        uiTemplate.setName("name");
+        uiTemplate.setConfiguration("configuration");
+        uiTemplate.setType(TemplateType.DASHBOARD.name());
+        uiTemplate.setActivated(BooleanUtils.TRUE);
+        uiTemplate.setDisabled(BooleanUtils.FALSE);
+
+        final UITemplate.Builder builder = new UITemplate.Builder();
+        final UITemplate uiTemplate2 = builder.map2Data(builder.data2Map(uiTemplate));
+
+        Assert.assertEquals(uiTemplate, uiTemplate2);
+
+        uiTemplate2.setConfiguration("configuration2");
+        uiTemplate.setType(TemplateType.TOPOLOGY_ENDPOINT.name());
+        uiTemplate.setActivated(BooleanUtils.FALSE);
+        uiTemplate.setDisabled(BooleanUtils.TRUE);
+        // Equals method is only for `name` field.
+        Assert.assertEquals(uiTemplate, uiTemplate2);
+    }
+}
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/oap-server/server-core/src/test/resources/endpoint-name-grouping.yml
similarity index 100%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to oap-server/server-core/src/test/resources/endpoint-name-grouping.yml
diff --git a/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml b/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml
new file mode 100644
index 0000000..9f55a1c
--- /dev/null
+++ b/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml
@@ -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.
+
+# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time.
+#
+# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file
+# could be added automatically.
+
+templates:
+  - name: "APM"
+    # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT.
+    # DASHBOARD type templates could have multiple definitions, by using different names.
+    # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only.
+    type: "DASHBOARD"
+    # Configuration could be defined through UI, and use `export` to format in the standard JSON.
+    configuration: |-
+      ui exported definition in JSONsdfsd
+      sdjfkasld
+      sdfui
+      skdfj:dafjisa
+      adifaosi
+    # Activated as the DASHBOARD type, makes this templates added into the UI page automatically.
+    # False means providing a basic template, user needs to add it manually.
+    activated: true
+    # True means wouldn't show up on the dashboard. Only keeps the definition in the storage.
+    # disabled: false
+  - name: "APM"
+    # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT.
+    # DASHBOARD type templates could have multiple definitions, by using different names.
+    # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only.
+    type: "DASHBOARD"
+    # Configuration could be defined through UI, and use `export` to format in the standard JSON.
+    configuration: |-
+      Mesh metrics configuration.
+    # Activated as the DASHBOARD type, makes this templates added into the UI page automatically.
+    # False means providing a basic template, user needs to add it manually.
+    # activated: true
+    # True means wouldn't show up on the dashboard. Only keeps the definition in the storage.
+    disabled: true
diff --git a/oap-server/server-core/src/test/resources/ui-initialized-templates.yml b/oap-server/server-core/src/test/resources/ui-initialized-templates.yml
new file mode 100644
index 0000000..2982491
--- /dev/null
+++ b/oap-server/server-core/src/test/resources/ui-initialized-templates.yml
@@ -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.
+
+# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time.
+#
+# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file
+# could be added automatically.
+
+templates:
+  - name: "APM (Agent based)"
+    # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT.
+    # DASHBOARD type templates could have multiple definitions, by using different names.
+    # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only.
+    type: "DASHBOARD"
+    # Configuration could be defined through UI, and use `export` to format in the standard JSON.
+    configuration: |-
+      ui exported definition in JSONsdfsd
+      sdjfkasld
+      sdfui
+      skdfj:dafjisa
+      adifaosi
+    # Activated as the DASHBOARD type, makes this templates added into the UI page automatically.
+    # False means providing a basic template, user needs to add it manually.
+    activated: true
+    # True means wouldn't show up on the dashboard. Only keeps the definition in the storage.
+    # disable: false
+  - name: "APM (Service Mesh)"
+    # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT.
+    # DASHBOARD type templates could have multiple definitions, by using different names.
+    # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only.
+    type: "DASHBOARD"
+    # Configuration could be defined through UI, and use `export` to format in the standard JSON.
+    configuration: |-
+      Mesh metrics configuration.
+    # Activated as the DASHBOARD type, makes this templates added into the UI page automatically.
+    # False means providing a basic template, user needs to add it manually.
+    # activated: true
+    # True means wouldn't show up on the dashboard. Only keeps the definition in the storage.
+    disabled: true
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
index ddcf103..7a5ba91 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
@@ -34,6 +34,7 @@ import org.apache.skywalking.oap.query.graphql.resolver.Query;
 import org.apache.skywalking.oap.query.graphql.resolver.TopNRecordsQuery;
 import org.apache.skywalking.oap.query.graphql.resolver.TopologyQuery;
 import org.apache.skywalking.oap.query.graphql.resolver.TraceQuery;
+import org.apache.skywalking.oap.query.graphql.resolver.UIConfigurationManagement;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.query.QueryModule;
 import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
@@ -70,46 +71,48 @@ public class GraphQLQueryProvider extends ModuleProvider {
     @Override
     public void prepare() throws ServiceNotProvidedException, ModuleStartException {
         GraphQLSchema schema = SchemaParser.newParser()
-                                           .file("query-protocol/common.graphqls")
-                                           .resolvers(new Query(), new Mutation())
-                                           .file("query-protocol/metadata.graphqls")
-                                           .resolvers(new MetadataQuery(getManager()))
-                                           .file("query-protocol/topology.graphqls")
-                                           .resolvers(new TopologyQuery(getManager()))
-                                           /**
-                                            * Metrics v2 query protocol is an alternative metrics query(s) of original v1,
-                                            * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls.
-                                            */
-                                           .file("query-protocol/metrics-v2.graphqls")
-                                           .resolvers(new MetricsQuery(getManager()))
-                                           ////////
-                                           //Deprecated Queries
-                                           ////////
-                                           .file("query-protocol/metric.graphqls")
-                                           .resolvers(new MetricQuery(getManager()))
-                                           .file("query-protocol/aggregation.graphqls")
-                                           .resolvers(new AggregationQuery(getManager()))
-                                           .file("query-protocol/top-n-records.graphqls")
-                                           .resolvers(new TopNRecordsQuery(getManager()))
-                                           ////////
-                                           .file("query-protocol/trace.graphqls")
-                                           .resolvers(new TraceQuery(getManager()))
-                                           .file("query-protocol/alarm.graphqls")
-                                           .resolvers(new AlarmQuery(getManager()))
-                                           .file("query-protocol/log.graphqls")
-                                           .resolvers(new LogQuery(getManager()))
-                                           .file("query-protocol/profile.graphqls")
-                                           .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager()))
-                                           .build()
-                                           .makeExecutableSchema();
+                .file("query-protocol/common.graphqls")
+                .resolvers(new Query(), new Mutation())
+                .file("query-protocol/metadata.graphqls")
+                .resolvers(new MetadataQuery(getManager()))
+                .file("query-protocol/topology.graphqls")
+                .resolvers(new TopologyQuery(getManager()))
+                /**
+                 * Metrics v2 query protocol is an alternative metrics query(s) of original v1,
+                 * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls.
+                 */
+                .file("query-protocol/metrics-v2.graphqls")
+                .resolvers(new MetricsQuery(getManager()))
+                ////////
+                //Deprecated Queries
+                ////////
+                .file("query-protocol/metric.graphqls")
+                .resolvers(new MetricQuery(getManager()))
+                .file("query-protocol/aggregation.graphqls")
+                .resolvers(new AggregationQuery(getManager()))
+                .file("query-protocol/top-n-records.graphqls")
+                .resolvers(new TopNRecordsQuery(getManager()))
+                ////////
+                .file("query-protocol/trace.graphqls")
+                .resolvers(new TraceQuery(getManager()))
+                .file("query-protocol/alarm.graphqls")
+                .resolvers(new AlarmQuery(getManager()))
+                .file("query-protocol/log.graphqls")
+                .resolvers(new LogQuery(getManager()))
+                .file("query-protocol/profile.graphqls")
+                .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager()))
+                .file("query-protocol/ui-configuration.graphqls")
+                .resolvers(new UIConfigurationManagement(getManager()))
+                .build()
+                .makeExecutableSchema();
         this.graphQL = GraphQL.newGraphQL(schema).build();
     }
 
     @Override
     public void start() throws ServiceNotProvidedException, ModuleStartException {
         JettyHandlerRegister service = getManager().find(CoreModule.NAME)
-                                                   .provider()
-                                                   .getService(JettyHandlerRegister.class);
+                .provider()
+                .getService(JettyHandlerRegister.class);
         service.addHandler(new GraphQLQueryHandler(config.getPath(), graphQL));
     }
 
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java
new file mode 100644
index 0000000..72fe595
--- /dev/null
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.query.graphql.resolver;
+
+import com.coxautodev.graphql.tools.GraphQLMutationResolver;
+import com.coxautodev.graphql.tools.GraphQLQueryResolver;
+import java.io.IOException;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+
+/**
+ * UI Configuration including dashboard, topology pop up page, is based on the available templates or manual configuration.
+ * UIConfigurationManagement provides the query and operations of templates.
+ *
+ * @since 8.0.0
+ */
+@RequiredArgsConstructor
+public class UIConfigurationManagement implements GraphQLQueryResolver, GraphQLMutationResolver {
+    private final ModuleManager manager;
+    private UITemplateManagementService uiTemplateManagementService;
+
+    private UITemplateManagementService getUITemplateManagementService() {
+        if (uiTemplateManagementService == null) {
+            this.uiTemplateManagementService = manager.find(CoreModule.NAME)
+                    .provider()
+                    .getService(UITemplateManagementService.class);
+        }
+        return uiTemplateManagementService;
+    }
+
+    public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) throws IOException {
+        if (includingDisabled == null) {
+            includingDisabled = false;
+        }
+        return getUITemplateManagementService().getAllTemplates(includingDisabled);
+    }
+
+    public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException {
+        return getUITemplateManagementService().addTemplate(setting);
+    }
+
+    public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException {
+        return getUITemplateManagementService().changeTemplate(setting);
+    }
+
+    public TemplateChangeStatus disableTemplate(String name) throws IOException {
+        return getUITemplateManagementService().disableTemplate(name);
+    }
+}
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index 3f44392..0b38f4e 160000
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit 3f44392c3b3502b4f3066e7ec89c794bc9ffb54d
+Subproject commit 0b38f4e1620ef66e6d9121845b2a55b090d2020f
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
index e5f51fb..9f591cb 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
@@ -35,6 +35,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
@@ -72,6 +73,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.Profi
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopNRecordsQueryEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopologyQueryEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TraceQueryEsDAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.UITemplateManagementEsDAO;
 
 /**
  * The storage provider for ElasticSearch 6.
@@ -112,7 +114,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
 
         if (!StringUtil.isEmpty(config.getSecretsManagementFile())) {
             MultipleFilesChangeMonitor monitor = new MultipleFilesChangeMonitor(
-                10, readableContents -> {
+                    10, readableContents -> {
                 final byte[] secretsFileContent = readableContents.get(0);
                 if (secretsFileContent == null) {
                     return;
@@ -140,39 +142,41 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
         }
 
         elasticSearchClient = new ElasticSearchClient(
-            config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
-            .getTrustStorePass(), config.getUser(), config.getPassword(),
-            indexNameConverters(config.getNameSpace())
+                config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
+                .getTrustStorePass(), config.getUser(), config.getPassword(),
+                indexNameConverters(config.getNameSpace())
         );
 
         this.registerServiceImplementation(
-            IBatchDAO.class, new BatchProcessEsDAO(elasticSearchClient, config.getBulkActions(), config
-                .getFlushInterval(), config.getConcurrentRequests()));
+                IBatchDAO.class, new BatchProcessEsDAO(elasticSearchClient, config.getBulkActions(), config
+                        .getFlushInterval(), config.getConcurrentRequests()));
         this.registerServiceImplementation(StorageDAO.class, new StorageEsDAO(elasticSearchClient));
         this.registerServiceImplementation(
-            IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearchClient));
+                IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearchClient));
         this.registerServiceImplementation(
-            INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(elasticSearchClient, config
-                .getResultWindowMaxSize()));
+                INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(elasticSearchClient, config
+                        .getResultWindowMaxSize()));
         this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(
-            ITraceQueryDAO.class, new TraceQueryEsDAO(elasticSearchClient, config.getSegmentQueryMaxSize()));
+                ITraceQueryDAO.class, new TraceQueryEsDAO(elasticSearchClient, config.getSegmentQueryMaxSize()));
         this.registerServiceImplementation(
-            IMetadataQueryDAO.class, new MetadataQueryEsDAO(elasticSearchClient, config.getMetadataQueryMaxSize()));
+                IMetadataQueryDAO.class, new MetadataQueryEsDAO(elasticSearchClient, config.getMetadataQueryMaxSize()));
         this.registerServiceImplementation(IAggregationQueryDAO.class, new AggregationQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(ILogQueryDAO.class, new LogQueryEsDAO(elasticSearchClient));
         this.registerServiceImplementation(
-            IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(elasticSearchClient, config
-                .getProfileTaskQueryMaxSize()));
+                IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(elasticSearchClient, config
+                        .getProfileTaskQueryMaxSize()));
         this.registerServiceImplementation(
-            IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(elasticSearchClient, config
-                .getProfileTaskQueryMaxSize()));
+                IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(elasticSearchClient, config
+                        .getProfileTaskQueryMaxSize()));
         this.registerServiceImplementation(
-            IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEsDAO(elasticSearchClient, config
-                .getProfileTaskQueryMaxSize()));
+                IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEsDAO(elasticSearchClient, config
+                        .getProfileTaskQueryMaxSize()));
+        this.registerServiceImplementation(
+                UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearchClient));
     }
 
     @Override
@@ -193,7 +197,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {CoreModule.NAME};
+        return new String[]{CoreModule.NAME};
     }
 
     public static List<IndexNameConverter> indexNameConverters(String namespace) {
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
similarity index 50%
copy from oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java
copy to oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
index b006055..604043a 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
@@ -18,34 +18,33 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
-import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.record.Record;
-import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
-import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
-import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
+import java.io.IOException;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
-import org.apache.skywalking.oap.server.core.storage.StorageDAO;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
+import org.elasticsearch.action.get.GetResponse;
+import org.elasticsearch.common.xcontent.XContentBuilder;
 
-public class StorageEsDAO extends EsDAO implements StorageDAO {
+public class ManagementEsDAO extends EsDAO implements IManagementDAO {
+    private final StorageBuilder<ManagementData> storageBuilder;
 
-    public StorageEsDAO(ElasticSearchClient client) {
+    public ManagementEsDAO(ElasticSearchClient client, StorageBuilder<ManagementData> storageBuilder) {
         super(client);
+        this.storageBuilder = storageBuilder;
     }
 
     @Override
-    public IMetricsDAO newMetricsDao(StorageBuilder<Metrics> storageBuilder) {
-        return new MetricsEsDAO(getClient(), storageBuilder);
-    }
+    public void insert(Model model, ManagementData managementData) throws IOException {
+        String modelName = model.getName();
+        final String id = managementData.id();
+        final GetResponse response = getClient().get(modelName, id);
+        if (response.isExists()) {
+            return;
+        }
 
-    @Override
-    public IRecordDAO newRecordDao(StorageBuilder<Record> storageBuilder) {
-        return new RecordEsDAO(getClient(), storageBuilder);
-    }
-
-    @Override
-    public INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder) {
-        return new NoneStreamEsDAO(getClient(), storageBuilder);
+        XContentBuilder builder = map2builder(storageBuilder.data2Map(managementData));
+        getClient().forceInsert(modelName, id, builder);
     }
-}
+}
\ No newline at end of file
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java
index b006055..08af9e6 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
@@ -48,4 +50,9 @@ public class StorageEsDAO extends EsDAO implements StorageDAO {
     public INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder) {
         return new NoneStreamEsDAO(getClient(), storageBuilder);
     }
+
+    @Override
+    public IManagementDAO newManagementDao(final StorageBuilder<ManagementData> storageBuilder) {
+        return new ManagementEsDAO(getClient(), storageBuilder);
+    }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java
new file mode 100644
index 0000000..f926d32
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.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.skywalking.oap.server.storage.plugin.elasticsearch.query;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
+import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
+import org.elasticsearch.action.get.GetResponse;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+
+@Slf4j
+public class UITemplateManagementEsDAO extends EsDAO implements UITemplateManagementDAO {
+    public UITemplateManagementEsDAO(ElasticSearchClient client) {
+        super(client);
+    }
+
+    @Override
+    public List<DashboardConfiguration> getAllTemplates(final Boolean includingDisabled) throws IOException {
+        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+
+        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+        if (!includingDisabled) {
+            boolQueryBuilder.must().add(QueryBuilders.termQuery(UITemplate.DISABLED, BooleanUtils.booleanToValue(includingDisabled)));
+        }
+
+        sourceBuilder.query(boolQueryBuilder);
+        //It is impossible we have 10000+ templates.
+        sourceBuilder.size(10000);
+
+        SearchResponse response = getClient().search(UITemplate.INDEX_NAME, sourceBuilder);
+
+        List<DashboardConfiguration> configs = new ArrayList<>();
+        final UITemplate.Builder builder = new UITemplate.Builder();
+        for (SearchHit searchHit : response.getHits()) {
+            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
+
+            final UITemplate uiTemplate = builder.map2Data(sourceAsMap);
+            configs.add(new DashboardConfiguration().fromEntity(uiTemplate));
+        }
+        return configs;
+    }
+
+    @Override
+    public TemplateChangeStatus addTemplate(final DashboardSetting setting) throws IOException {
+        try {
+            final UITemplate.Builder builder = new UITemplate.Builder();
+            final UITemplate uiTemplate = setting.toEntity();
+
+            final GetResponse response = getClient().get(UITemplate.INDEX_NAME, uiTemplate.id());
+            if (response.isExists()) {
+                return TemplateChangeStatus.builder().status(false).message("Template exists").build();
+            }
+
+            XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate));
+            getClient().forceInsert(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder);
+            return TemplateChangeStatus.builder().status(true).build();
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return TemplateChangeStatus.builder().status(false).message("Can't add a new template").build();
+        }
+    }
+
+    @Override
+    public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException {
+        try {
+            final UITemplate.Builder builder = new UITemplate.Builder();
+            final UITemplate uiTemplate = setting.toEntity();
+
+            final GetResponse response = getClient().get(UITemplate.INDEX_NAME, uiTemplate.id());
+            if (!response.isExists()) {
+                return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+            }
+
+            XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate));
+            getClient().forceUpdate(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder);
+            return TemplateChangeStatus.builder().status(true).build();
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+        }
+    }
+
+    @Override
+    public TemplateChangeStatus disableTemplate(final String name) throws IOException {
+        final GetResponse response = getClient().get(UITemplate.INDEX_NAME, name);
+        if (response.isExists()) {
+            final UITemplate.Builder builder = new UITemplate.Builder();
+            final UITemplate uiTemplate = builder.map2Data(response.getSourceAsMap());
+            uiTemplate.setDisabled(BooleanUtils.TRUE);
+
+            XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate));
+            getClient().forceUpdate(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder);
+            return TemplateChangeStatus.builder().status(true).build();
+        } else {
+            return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
index aa740df..c69d399 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
@@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
@@ -58,6 +59,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.Profi
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.ProfileTaskQueryEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopNRecordsQueryEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopologyQueryEsDAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.UITemplateManagementEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.base.StorageEs7Installer;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.client.ElasticSearch7Client;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.dao.StorageEs7DAO;
@@ -106,7 +108,7 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
         }
         if (!StringUtil.isEmpty(config.getSecretsManagementFile())) {
             MultipleFilesChangeMonitor monitor = new MultipleFilesChangeMonitor(
-                10, readableContents -> {
+                    10, readableContents -> {
                 final byte[] secretsFileContent = readableContents.get(0);
                 if (secretsFileContent == null) {
                     return;
@@ -134,50 +136,52 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
         }
 
         elasticSearch7Client = new ElasticSearch7Client(
-            config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
-            .getTrustStorePass(), config.getUser(), config.getPassword(),
-            indexNameConverters(config.getNameSpace())
+                config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
+                .getTrustStorePass(), config.getUser(), config.getPassword(),
+                indexNameConverters(config.getNameSpace())
         );
 
         this.registerServiceImplementation(
-            IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(),
-                                                   config.getFlushInterval(), config.getConcurrentRequests()
-            ));
+                IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(),
+                        config.getFlushInterval(), config.getConcurrentRequests()
+                ));
         this.registerServiceImplementation(StorageDAO.class, new StorageEs7DAO(elasticSearch7Client));
         this.registerServiceImplementation(
-            IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client));
+                IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client));
         this.registerServiceImplementation(
-            INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(
-                elasticSearch7Client,
-                config.getResultWindowMaxSize()
-            ));
+                INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(
+                        elasticSearch7Client,
+                        config.getResultWindowMaxSize()
+                ));
         this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQueryEsDAO(elasticSearch7Client));
         this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEs7DAO(elasticSearch7Client));
         this.registerServiceImplementation(
-            ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize()));
+                ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize()));
         this.registerServiceImplementation(
-            IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize()));
+                IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize()));
         this.registerServiceImplementation(
-            IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client));
+                IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client));
         this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQueryEs7DAO(elasticSearch7Client));
         this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQueryEsDAO(elasticSearch7Client));
         this.registerServiceImplementation(ILogQueryDAO.class, new LogQueryEs7DAO(elasticSearch7Client));
 
         this.registerServiceImplementation(
-            IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(
-                elasticSearch7Client,
-                config.getProfileTaskQueryMaxSize()
-            ));
+                IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(
+                        elasticSearch7Client,
+                        config.getProfileTaskQueryMaxSize()
+                ));
         this.registerServiceImplementation(
-            IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(
-                elasticSearch7Client,
-                config.getProfileTaskQueryMaxSize()
-            ));
+                IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(
+                        elasticSearch7Client,
+                        config.getProfileTaskQueryMaxSize()
+                ));
         this.registerServiceImplementation(
-            IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO(
-                elasticSearch7Client,
-                config.getProfileTaskQueryMaxSize()
-            ));
+                IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO(
+                        elasticSearch7Client,
+                        config.getProfileTaskQueryMaxSize()
+                ));
+        this.registerServiceImplementation(
+                UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearch7Client));
     }
 
     @Override
@@ -198,6 +202,6 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {CoreModule.NAME};
+        return new String[]{CoreModule.NAME};
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java
index 60655ff..5161e0a 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.dao;
 
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
@@ -28,6 +30,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
 import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.ManagementEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.NoneStreamEsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.RecordEsDAO;
 
@@ -51,4 +54,9 @@ public class StorageEs7DAO extends EsDAO implements StorageDAO {
     public INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder) {
         return new NoneStreamEsDAO(getClient(), storageBuilder);
     }
+
+    @Override
+    public IManagementDAO newManagementDao(final StorageBuilder<ManagementData> storageBuilder) {
+        return new ManagementEsDAO(getClient(), storageBuilder);
+    }
 }
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
index 380ca1d..13d7eda 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
@@ -26,6 +26,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
@@ -58,6 +59,7 @@ import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.ProfileThr
 import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TopNRecordsQuery;
 import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TopologyQuery;
 import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TraceQuery;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.UITemplateManagementDAOImpl;
 
 @Slf4j
 public class InfluxStorageProvider extends ModuleProvider {
@@ -103,12 +105,13 @@ public class InfluxStorageProvider extends ModuleProvider {
 
         this.registerServiceImplementation(IProfileTaskQueryDAO.class, new ProfileTaskQuery(client));
         this.registerServiceImplementation(
-            IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client));
+                IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client));
         this.registerServiceImplementation(
-            IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize()));
+                IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize()));
 
         this.registerServiceImplementation(
-            IHistoryDeleteDAO.class, new HistoryDeleteDAO(client));
+                IHistoryDeleteDAO.class, new HistoryDeleteDAO(client));
+        this.registerServiceImplementation(UITemplateManagementDAO.class, new UITemplateManagementDAOImpl(client));
     }
 
     @Override
@@ -130,6 +133,6 @@ public class InfluxStorageProvider extends ModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {CoreModule.NAME};
+        return new String[]{CoreModule.NAME};
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java
index 77e69ed..45553d0 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.oap.server.storage.plugin.influxdb.base;
 
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
@@ -49,4 +51,9 @@ public class InfluxStorageDAO implements StorageDAO {
     public INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder) {
         return new NoneStreamDAO(influxClient, storageBuilder);
     }
+
+    @Override
+    public IManagementDAO newManagementDao(final StorageBuilder<ManagementData> storageBuilder) {
+        return new ManagementDAO(influxClient, storageBuilder);
+    }
 }
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java
new file mode 100644
index 0000000..b45bc41
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.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.skywalking.oap.server.storage.plugin.influxdb.base;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.analysis.manual.service.ServiceTraffic;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
+import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.TableMetaInfo;
+import org.influxdb.dto.QueryResult;
+import org.influxdb.querybuilder.SelectQueryImpl;
+import org.influxdb.querybuilder.WhereQueryImpl;
+
+import static org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants.ID_COLUMN;
+import static org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants.NAME;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select;
+
+@Slf4j
+public class ManagementDAO implements IManagementDAO {
+    private static final long STATIC_TIMESTAMP = 1_000_000;
+
+    private InfluxClient client;
+    private StorageBuilder<ManagementData> storageBuilder;
+
+    public ManagementDAO(InfluxClient client, StorageBuilder<ManagementData> storageBuilder) {
+        this.client = client;
+        this.storageBuilder = storageBuilder;
+    }
+
+    @Override
+    public void insert(final Model model, final ManagementData managementData) throws IOException {
+        final WhereQueryImpl<SelectQueryImpl> query = select()
+                .column(ID_COLUMN).column(NAME)
+                .from(ServiceTraffic.INDEX_NAME)
+                .where(eq(ID_COLUMN, managementData.id()));
+        QueryResult.Series series = client.queryForSingleSeries(query);
+        if (log.isDebugEnabled()) {
+            log.debug("SQL: {} result: {}", query.getCommand(), series);
+        }
+        if (series != null && series.getValues().size() > 0) {
+            return;
+        }
+
+        final InfluxInsertRequest request = new InfluxInsertRequest(model, managementData, storageBuilder)
+                .time(STATIC_TIMESTAMP, TimeUnit.NANOSECONDS);
+        TableMetaInfo.get(model.getName()).getStorageAndTagMap().forEach((field, tag) -> {
+            request.addFieldAsTag(field, tag);
+        });
+        client.write(request.getPoint());
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
index 4c20e08..6b0d838 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
@@ -29,6 +29,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.NodeType;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
@@ -59,15 +60,12 @@ import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq;
 import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.gte;
 import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select;
 
+@RequiredArgsConstructor
 @Slf4j
 public class MetadataQuery implements IMetadataQueryDAO {
     private static final Gson GSON = new Gson();
     private final InfluxClient client;
 
-    public MetadataQuery(final InfluxClient client) {
-        this.client = client;
-    }
-
     @Override
     public List<Service> getAllServices(final long startTimestamp, final long endTimestamp) throws IOException {
         SelectSubQueryImpl<SelectQueryImpl> subQuery = select()
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java
new file mode 100644
index 0000000..ddc3359
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.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.skywalking.oap.server.storage.plugin.influxdb.query;
+
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants;
+import org.influxdb.dto.Point;
+import org.influxdb.dto.QueryResult;
+import org.influxdb.querybuilder.SelectQueryImpl;
+import org.influxdb.querybuilder.WhereQueryImpl;
+
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select;
+
+@RequiredArgsConstructor
+@Slf4j
+public class UITemplateManagementDAOImpl implements UITemplateManagementDAO {
+    private final InfluxClient client;
+
+    @Override
+    public List<DashboardConfiguration> getAllTemplates(final Boolean includingDisabled) throws IOException {
+        WhereQueryImpl<SelectQueryImpl> where = select().raw("*::field")
+                                                        .from(client.getDatabase(), UITemplate.INDEX_NAME)
+                                                        .where();
+        if (!includingDisabled) {
+            where.and(eq(UITemplate.DISABLED, BooleanUtils.FALSE));
+        }
+        final QueryResult.Series series = client.queryForSingleSeries(where);
+        final List<DashboardConfiguration> configs = new ArrayList<>();
+        final UITemplate.Builder builder = new UITemplate.Builder();
+        if (Objects.nonNull(series)) {
+            List<String> columnNames = series.getColumns();
+
+            final int size = series.getValues().size();
+            for (int offset = 0; offset < size; offset++) {
+                List<Object> columnValues = series.getValues().get(offset);
+
+                Map<String, Object> data = Maps.newHashMap();
+                for (int i = 1; i < columnNames.size(); i++) {
+                    data.put(columnNames.get(i), columnValues.get(i));
+                }
+                UITemplate uiTemplate = builder.map2Data(data);
+                configs.add(new DashboardConfiguration().fromEntity(uiTemplate));
+            }
+        }
+        return configs;
+    }
+
+    @Override
+    public TemplateChangeStatus addTemplate(final DashboardSetting setting) {
+        final UITemplate.Builder builder = new UITemplate.Builder();
+        final UITemplate uiTemplate = setting.toEntity();
+
+        Point point = Point.measurement(UITemplate.INDEX_NAME)
+                           .tag(InfluxConstants.TagName.ID_COLUMN, uiTemplate.id())
+                           .fields(builder.data2Map(uiTemplate))
+                           .time(0L, TimeUnit.MILLISECONDS)
+                           .build();
+        client.write(point);
+        return TemplateChangeStatus.builder().status(true).build();
+    }
+
+    @Override
+    public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException {
+        final UITemplate.Builder builder = new UITemplate.Builder();
+        final UITemplate uiTemplate = setting.toEntity();
+
+        WhereQueryImpl<SelectQueryImpl> query = select().all()
+                                                        .from(client.getDatabase(), UITemplate.INDEX_NAME)
+                                                        .where(eq(InfluxConstants.TagName.ID_COLUMN, uiTemplate.id()));
+
+        QueryResult.Series series = client.queryForSingleSeries(query);
+        if (Objects.nonNull(series)) {
+            Point point = Point.measurement(UITemplate.INDEX_NAME)
+                               .fields(builder.data2Map(uiTemplate))
+                               .tag(series.getTags())
+                               .time(0L, TimeUnit.MILLISECONDS)
+                               .build();
+            client.write(point);
+            return TemplateChangeStatus.builder().status(true).build();
+        } else {
+            return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+        }
+    }
+
+    @Override
+    public TemplateChangeStatus disableTemplate(final String name) throws IOException {
+        WhereQueryImpl<SelectQueryImpl> query = select().all()
+                                                        .from(client.getDatabase(), UITemplate.INDEX_NAME)
+                                                        .where(eq(InfluxConstants.NAME, name));
+        QueryResult.Series series = client.queryForSingleSeries(query);
+        if (Objects.nonNull(series)) {
+            List<String> columnNames = series.getColumns();
+            List<Object> columnValues = series.getValues().get(0);
+
+            Map<String, Object> storageData = Maps.newHashMap();
+            for (int i = 1; i < columnNames.size(); i++) {
+                storageData.put(columnNames.get(i), columnValues.get(i));
+            }
+
+            storageData.put(UITemplate.DISABLED, BooleanUtils.TRUE);
+            Point point = Point.measurement(UITemplate.INDEX_NAME)
+                               .tag(series.getTags())
+                               .fields(storageData)
+                               .time(0L, TimeUnit.MILLISECONDS)
+                               .build();
+            client.write(point);
+            return TemplateChangeStatus.builder().status(true).build();
+        } else {
+            return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
index f7ed999..af5b6e5 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
@@ -27,6 +27,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
@@ -61,6 +62,7 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TableInstal
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecordsQueryDAO;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TraceQueryDAO;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO;
 
 /**
  * H2 Storage provider is for demonstration and preview only. I will find that haven't implemented several interfaces,
@@ -106,24 +108,25 @@ public class H2StorageProvider extends ModuleProvider {
         this.registerServiceImplementation(StorageDAO.class, new H2StorageDAO(h2Client));
 
         this.registerServiceImplementation(
-            INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(h2Client));
+                INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(h2Client));
 
         this.registerServiceImplementation(ITopologyQueryDAO.class, new H2TopologyQueryDAO(h2Client));
         this.registerServiceImplementation(IMetricsQueryDAO.class, new H2MetricsQueryDAO(h2Client));
         this.registerServiceImplementation(ITraceQueryDAO.class, new H2TraceQueryDAO(h2Client));
         this.registerServiceImplementation(
-            IMetadataQueryDAO.class, new H2MetadataQueryDAO(h2Client, config.getMetadataQueryMaxSize()));
+                IMetadataQueryDAO.class, new H2MetadataQueryDAO(h2Client, config.getMetadataQueryMaxSize()));
         this.registerServiceImplementation(IAggregationQueryDAO.class, new H2AggregationQueryDAO(h2Client));
         this.registerServiceImplementation(IAlarmQueryDAO.class, new H2AlarmQueryDAO(h2Client));
         this.registerServiceImplementation(
-            IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(h2Client));
+                IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(h2Client));
         this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new H2TopNRecordsQueryDAO(h2Client));
         this.registerServiceImplementation(ILogQueryDAO.class, new H2LogQueryDAO(h2Client));
 
         this.registerServiceImplementation(IProfileTaskQueryDAO.class, new H2ProfileTaskQueryDAO(h2Client));
         this.registerServiceImplementation(IProfileTaskLogQueryDAO.class, new H2ProfileTaskLogQueryDAO(h2Client));
         this.registerServiceImplementation(
-            IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(h2Client));
+                IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(h2Client));
+        this.registerServiceImplementation(UITemplateManagementDAO.class, new H2UITemplateManagementDAO(h2Client));
     }
 
     @Override
@@ -145,6 +148,6 @@ public class H2StorageProvider extends ModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {CoreModule.NAME};
+        return new String[]{CoreModule.NAME};
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java
new file mode 100644
index 0000000..5c44590
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.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.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
+import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
+import org.apache.skywalking.oap.server.core.storage.StorageData;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
+
+/**
+ * Synchronize storage H2 implements
+ */
+public class H2ManagementDAO extends H2SQLExecutor implements IManagementDAO {
+
+    private JDBCHikariCPClient h2Client;
+    private StorageBuilder<ManagementData> storageBuilder;
+
+    public H2ManagementDAO(JDBCHikariCPClient h2Client, StorageBuilder<ManagementData> storageBuilder) {
+        this.h2Client = h2Client;
+        this.storageBuilder = storageBuilder;
+    }
+
+    @Override
+    public void insert(Model model, ManagementData storageData) throws IOException {
+        try (Connection connection = h2Client.getConnection()) {
+            final StorageData data = getByID(h2Client, model.getName(), storageData.id(), storageBuilder);
+            if (data != null) {
+                return;
+            }
+
+            SQLExecutor insertExecutor = getInsertExecutor(model.getName(), storageData, storageBuilder);
+            insertExecutor.invoke(connection);
+        } catch (IOException | SQLException e) {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java
index 2a8ae22..0b2bdf1 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
 
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
+import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
+import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
@@ -50,4 +52,9 @@ public class H2StorageDAO implements StorageDAO {
     public INoneStreamDAO newNoneStreamDao(StorageBuilder<NoneStream> storageBuilder) {
         return new H2NoneStreamDAO(h2Client, storageBuilder);
     }
+
+    @Override
+    public IManagementDAO newManagementDao(final StorageBuilder<ManagementData> storageBuilder) {
+        return new H2ManagementDAO(h2Client, storageBuilder);
+    }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java
new file mode 100644
index 0000000..8802b28
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
+import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
+import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration;
+import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
+import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.util.BooleanUtils;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
+
+@Slf4j
+@RequiredArgsConstructor
+public class H2UITemplateManagementDAO extends H2SQLExecutor implements UITemplateManagementDAO {
+    private final JDBCHikariCPClient h2Client;
+
+    @Override
+    public List<DashboardConfiguration> getAllTemplates(final Boolean includingDisabled) throws IOException {
+        final StringBuilder sql = new StringBuilder();
+        final ArrayList<Object> condition = new ArrayList<>(1);
+        sql.append("select * from ").append(UITemplate.INDEX_NAME).append(" where 1=1 ");
+        if (!includingDisabled) {
+            sql.append(" and ").append(UITemplate.DISABLED).append("=?");
+            condition.add(BooleanUtils.booleanToValue(includingDisabled));
+        }
+
+        try (Connection connection = h2Client.getConnection()) {
+            try (ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]))) {
+                final List<DashboardConfiguration> configs = new ArrayList<>();
+                final UITemplate.Builder builder = new UITemplate.Builder();
+                UITemplate uiTemplate = null;
+                do {
+                    uiTemplate = (UITemplate) toStorageData(resultSet, UITemplate.INDEX_NAME, builder);
+                    if (uiTemplate != null) {
+                        configs.add(new DashboardConfiguration().fromEntity(uiTemplate));
+                    }
+                } while (uiTemplate != null);
+                return configs;
+            }
+        } catch (SQLException | JDBCClientException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public TemplateChangeStatus addTemplate(final DashboardSetting setting) throws IOException {
+        final UITemplate uiTemplate = setting.toEntity();
+        final SQLExecutor insertExecutor = getInsertExecutor(UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder());
+        try (Connection connection = h2Client.getConnection()) {
+            insertExecutor.invoke(connection);
+            return TemplateChangeStatus.builder().status(true).build();
+        } catch (SQLException | JDBCClientException e) {
+            log.error(e.getMessage(), e);
+            return TemplateChangeStatus.builder().status(false).message("Can't add a new template").build();
+        }
+    }
+
+    @Override
+    public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException {
+        final UITemplate uiTemplate = setting.toEntity();
+        return executeUpdate(uiTemplate);
+    }
+
+    @Override
+    public TemplateChangeStatus disableTemplate(final String name) throws IOException {
+        final UITemplate uiTemplate = (UITemplate) getByID(h2Client, UITemplate.INDEX_NAME, name, new UITemplate.Builder());
+        if (uiTemplate == null) {
+            return TemplateChangeStatus.builder().status(false).message("Can't find the template").build();
+        }
+        uiTemplate.setDisabled(BooleanUtils.TRUE);
+        return executeUpdate(uiTemplate);
+    }
+
+    private TemplateChangeStatus executeUpdate(final UITemplate uiTemplate) throws IOException {
+        final SQLExecutor updateExecutor = getUpdateExecutor(UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder());
+        try (Connection connection = h2Client.getConnection()) {
+            updateExecutor.invoke(connection);
+            return TemplateChangeStatus.builder().status(true).build();
+        } catch (SQLException | JDBCClientException e) {
+            log.error(e.getMessage(), e);
+            return TemplateChangeStatus.builder().status(false).message("Can't add/update the template").build();
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
index 33c1530..11a39bc 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
@@ -26,6 +26,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
+import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.model.ModelCreator;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO;
@@ -55,6 +56,7 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2ProfileThre
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2StorageDAO;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecordsQueryDAO;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO;
 
 /**
  * MySQL storage provider should be secondary choice for production usage as SkyWalking storage solution. It enhanced
@@ -96,24 +98,25 @@ public class MySQLStorageProvider extends ModuleProvider {
         this.registerServiceImplementation(IBatchDAO.class, new H2BatchDAO(mysqlClient));
         this.registerServiceImplementation(StorageDAO.class, new H2StorageDAO(mysqlClient));
         this.registerServiceImplementation(
-            INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(mysqlClient));
+                INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(mysqlClient));
 
         this.registerServiceImplementation(ITopologyQueryDAO.class, new H2TopologyQueryDAO(mysqlClient));
         this.registerServiceImplementation(IMetricsQueryDAO.class, new H2MetricsQueryDAO(mysqlClient));
         this.registerServiceImplementation(ITraceQueryDAO.class, new MySQLTraceQueryDAO(mysqlClient));
         this.registerServiceImplementation(
-            IMetadataQueryDAO.class, new H2MetadataQueryDAO(mysqlClient, config.getMetadataQueryMaxSize()));
+                IMetadataQueryDAO.class, new H2MetadataQueryDAO(mysqlClient, config.getMetadataQueryMaxSize()));
         this.registerServiceImplementation(IAggregationQueryDAO.class, new MySQLAggregationQueryDAO(mysqlClient));
         this.registerServiceImplementation(IAlarmQueryDAO.class, new MySQLAlarmQueryDAO(mysqlClient));
         this.registerServiceImplementation(
-            IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(mysqlClient));
+                IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(mysqlClient));
         this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new H2TopNRecordsQueryDAO(mysqlClient));
         this.registerServiceImplementation(ILogQueryDAO.class, new MySQLLogQueryDAO(mysqlClient));
 
         this.registerServiceImplementation(IProfileTaskQueryDAO.class, new H2ProfileTaskQueryDAO(mysqlClient));
         this.registerServiceImplementation(IProfileTaskLogQueryDAO.class, new H2ProfileTaskLogQueryDAO(mysqlClient));
         this.registerServiceImplementation(
-            IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(mysqlClient));
+                IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(mysqlClient));
+        this.registerServiceImplementation(UITemplateManagementDAO.class, new H2UITemplateManagementDAO(mysqlClient));
     }
 
     @Override
@@ -135,6 +138,6 @@ public class MySQLStorageProvider extends ModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {CoreModule.NAME};
+        return new String[]{CoreModule.NAME};
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
index 609140c..55a6b51 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
@@ -74,12 +74,12 @@ public class MySQLTableInstaller extends H2TableInstaller {
             if (!modelColumn.isStorageOnly()) {
                 SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX ");
                 tableIndexSQL.append(model.getName().toUpperCase())
-                             .append("_")
-                             .append(String.valueOf(indexSeq++))
-                             .append("_IDX ");
+                        .append("_")
+                        .append(String.valueOf(indexSeq++))
+                        .append("_IDX ");
                 tableIndexSQL.append("ON ").append(model.getName()).append("(")
-                             .append(modelColumn.getColumnName().getStorageName())
-                             .append(")");
+                        .append(modelColumn.getColumnName().getStorageName())
+                        .append(")");
                 createIndex(client, connection, model, tableIndexSQL);
             }
         }
@@ -87,9 +87,9 @@ public class MySQLTableInstaller extends H2TableInstaller {
         for (final ExtraQueryIndex extraQueryIndex : model.getExtraQueryIndices()) {
             SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX ");
             tableIndexSQL.append(model.getName().toUpperCase())
-                         .append("_")
-                         .append(String.valueOf(indexSeq++))
-                         .append("_IDX ");
+                    .append("_")
+                    .append(String.valueOf(indexSeq++))
+                    .append("_IDX ");
             tableIndexSQL.append(" ON ").append(model.getName()).append("(");
             final String[] columns = extraQueryIndex.getColumns();
             for (int i = 0; i < columns.length; i++) {
@@ -105,8 +105,15 @@ public class MySQLTableInstaller extends H2TableInstaller {
 
     @Override
     protected String getColumnType(final ModelColumn column) {
-        if (StorageDataComplexObject.class.isAssignableFrom(column.getType())) {
+        final Class<?> type = column.getType();
+        if (StorageDataComplexObject.class.isAssignableFrom(type)) {
             return "MEDIUMTEXT";
+        } else if (String.class.equals(type)) {
+            if (column.getLength() > 16383) {
+                return "MEDIUMTEXT";
+            } else {
+                return "VARCHAR(" + column.getLength() + ")";
+            }
         }
         return super.getColumnType(column);
     }
diff --git a/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java b/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java
index 456a012..5cdf423 100644
--- a/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java
+++ b/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java
@@ -30,7 +30,7 @@ public class ModuleProviderTesting implements ModuleServiceHolder {
 
     @Override
     public void registerServiceImplementation(Class<? extends Service> serviceType,
-        Service service) throws ServiceNotProvidedException {
+                                              Service service) throws ServiceNotProvidedException {
         if (serviceType.isInstance(service)) {
             this.services.put(serviceType, service);
         } else {
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
index 2e60292..71f1d9a 100755
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
@@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService;
 import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
 import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping;
+import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService;
 import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
 import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
 import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
@@ -99,8 +100,8 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
     @Override
     public void prepare() throws ServiceNotProvidedException, ModuleStartException {
         this.registerServiceImplementation(
-            NamingControl.class,
-            new NamingControl(50, 50, 150, new EndpointNameGrouping())
+                NamingControl.class,
+                new NamingControl(50, 50, 150, new EndpointNameGrouping())
         );
 
         MockStreamAnnotationListener streamAnnotationListener = new MockStreamAnnotationListener(getManager());
@@ -119,13 +120,13 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
         CoreModuleConfig moduleConfig = new CoreModuleConfig();
         this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig));
         this.registerServiceImplementation(
-            DownSamplingConfigService.class, new DownSamplingConfigService(Collections.emptyList()));
+                DownSamplingConfigService.class, new DownSamplingConfigService(Collections.emptyList()));
 
         this.registerServiceImplementation(GRPCHandlerRegister.class, new MockGRPCHandlerRegister());
         this.registerServiceImplementation(JettyHandlerRegister.class, new MockJettyHandlerRegister());
 
         this.registerServiceImplementation(
-            IComponentLibraryCatalogService.class, new MockComponentLibraryCatalogService());
+                IComponentLibraryCatalogService.class, new MockComponentLibraryCatalogService());
 
         this.registerServiceImplementation(SourceReceiver.class, new MockSourceReceiver());
 
@@ -139,7 +140,7 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
         this.registerServiceImplementation(ModelManipulator.class, storageModels);
 
         this.registerServiceImplementation(
-            NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
+                NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
 
         this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager()));
         this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
@@ -153,9 +154,9 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
 
         // add profile service implementations
         this.registerServiceImplementation(
-            ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager()));
+                ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager()));
         this.registerServiceImplementation(
-            ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig));
+                ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig));
         this.registerServiceImplementation(ProfileTaskCache.class, new ProfileTaskCache(getManager(), moduleConfig));
 
         this.registerServiceImplementation(CommandService.class, new CommandService(getManager()));
@@ -164,6 +165,9 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
 
         // add oal engine loader service implementations
         this.registerServiceImplementation(OALEngineLoaderService.class, new OALEngineLoaderService(getManager()));
+
+        // Management
+        this.registerServiceImplementation(UITemplateManagementService.class, new UITemplateManagementService(getManager()));
     }
 
     @Override
@@ -181,8 +185,8 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
 
     @Override
     public String[] requiredModules() {
-        return new String[] {
-            TelemetryModule.NAME
+        return new String[]{
+                TelemetryModule.NAME
         };
     }
 }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java
index c39c00e..a2b0819 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Annotation;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.analysis.Stream;
 import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener;
-import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor;
+import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.annotation.AnnotationListener;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
@@ -51,8 +51,8 @@ public class MockStreamAnnotationListener implements AnnotationListener {
 
             if (stream.processor().equals(RecordStreamProcessor.class)) {
                 RecordStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
-            } else if (stream.processor().equals(NoneStreamingProcessor.class)) {
-                NoneStreamingProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
+            } else if (stream.processor().equals(NoneStreamProcessor.class)) {
+                NoneStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass);
             }
         } else {
             throw new UnexpectedException(
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java
new file mode 100644
index 0000000..a6514dc
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.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.skywalking.e2e;
+
+import com.google.common.io.Resources;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.skywalking.e2e.dashboard.DashboardConfiguration;
+import org.apache.skywalking.e2e.dashboard.DashboardConfigurationListWrapper;
+import org.apache.skywalking.e2e.dashboard.DashboardSetting;
+import org.apache.skywalking.e2e.dashboard.TemplateChangeStatus;
+import org.apache.skywalking.e2e.dashboard.TemplateChangeStatusWrapper;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+
+public class UIConfigurationManagementClient extends SimpleQueryClient {
+
+    public UIConfigurationManagementClient(final String endpointUrl) {
+        super(endpointUrl);
+    }
+
+    public UIConfigurationManagementClient(final String host, final int port) {
+        super(host, port);
+    }
+
+    public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException {
+        final URL queryFileUrl = Resources.getResource("ui-addTemplate.gql");
+        final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
+                                            .stream()
+                                            .filter(it -> !it.startsWith("#"))
+                                            .collect(Collectors.joining())
+                                            .replace("{name}", setting.name())
+                                            .replace("{type}", String.valueOf(setting.type()))
+                                            .replace("{configuration}", setting.configuration())
+                                            .replace("{active}", String.valueOf(setting.active()));
+
+        final ResponseEntity<GQLResponse<TemplateChangeStatusWrapper>> responseEntity = restTemplate.exchange(
+            new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)),
+            new ParameterizedTypeReference<GQLResponse<TemplateChangeStatusWrapper>>() {
+            }
+        );
+
+        if (responseEntity.getStatusCode() != HttpStatus.OK) {
+            throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode());
+        }
+
+        return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult();
+    }
+
+    public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) throws IOException {
+        final URL queryFileUrl = Resources.getResource("ui-getTemplates.gql");
+        final String queryString =
+            Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
+                     .stream()
+                     .filter(it -> !it.startsWith("#"))
+                     .collect(Collectors.joining())
+                     .replace("{includingDisabled}", String.valueOf(includingDisabled));
+
+        final ResponseEntity<GQLResponse<DashboardConfigurationListWrapper>> responseEntity = restTemplate.exchange(
+            new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)),
+            new ParameterizedTypeReference<GQLResponse<DashboardConfigurationListWrapper>>() {
+            }
+        );
+
+        if (responseEntity.getStatusCode() != HttpStatus.OK) {
+            throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode());
+        }
+
+        return Objects.requireNonNull(responseEntity.getBody()).getData().getConfigurations();
+    }
+
+    public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException {
+
+        final URL queryFileUrl = Resources.getResource("ui-changeTemplate.gql");
+        final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
+                                            .stream()
+                                            .filter(it -> !it.startsWith("#"))
+                                            .collect(Collectors.joining())
+                                            .replace("{name}", setting.name())
+                                            .replace("{type}", String.valueOf(setting.type()))
+                                            .replace("{configuration}", setting.configuration())
+                                            .replace("{active}", String.valueOf(setting.active()));
+
+        final ResponseEntity<GQLResponse<TemplateChangeStatusWrapper>> responseEntity = restTemplate.exchange(
+            new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)),
+            new ParameterizedTypeReference<GQLResponse<TemplateChangeStatusWrapper>>() {
+            }
+        );
+
+        if (responseEntity.getStatusCode() != HttpStatus.OK) {
+            throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode());
+        }
+
+        return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult();
+    }
+
+    public TemplateChangeStatus disableTemplate(String name) throws IOException {
+
+        final URL queryFileUrl = Resources.getResource("ui-disableTemplate.gql");
+        final String queryString =
+            Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
+                     .stream()
+                     .filter(it -> !it.startsWith("#"))
+                     .collect(Collectors.joining())
+                     .replace("{name}", name);
+
+        final ResponseEntity<GQLResponse<TemplateChangeStatusWrapper>> responseEntity = restTemplate.exchange(
+            new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)),
+            new ParameterizedTypeReference<GQLResponse<TemplateChangeStatusWrapper>>() {
+            }
+        );
+
+        if (responseEntity.getStatusCode() != HttpStatus.OK) {
+            throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode());
+        }
+
+        return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult();
+    }
+
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java
index c0756b4..778d5e9 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java
@@ -16,16 +16,15 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Data;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
-    }
+@Data
+public class DashboardConfiguration {
+    private String name;
+    private TemplateType type;
+    private String configuration;
+    private boolean activated;
+    private boolean disabled;
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java
index c0756b4..61924b4 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java
@@ -16,16 +16,13 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.List;
+import lombok.Data;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+@Data
+public class DashboardConfigurationListWrapper {
 
-        Assert.assertEquals(30, coreModule.services().length);
-    }
+    private List<DashboardConfiguration> configurations;
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java
similarity index 50%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java
index c0756b4..417f109 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java
@@ -16,16 +16,25 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Data;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+@Data
+public class DashboardConfigurationMatcher extends AbstractMatcher<DashboardConfiguration> {
+    private String name;
+    private String type;
+    private String configuration;
+    private String activated;
+    private String disabled;
 
-        Assert.assertEquals(30, coreModule.services().length);
+    @Override
+    public void verify(final DashboardConfiguration configuration) {
+        doVerify(this.name, configuration.getName());
+        doVerify(this.type, String.valueOf(configuration.getType()));
+        doVerify(this.configuration, configuration.getConfiguration());
+        doVerify(this.activated, String.valueOf(configuration.isActivated()));
+        doVerify(this.disabled, String.valueOf(configuration.isDisabled()));
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java
index c0756b4..128f08b 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java
@@ -16,16 +16,16 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.List;
+import lombok.Data;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+@Data
+public class DashboardConfigurations {
+    private List<DashboardConfiguration> configurations;
 
-        Assert.assertEquals(30, coreModule.services().length);
+    public int size() {
+        return configurations.size();
     }
 }
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java
new file mode 100644
index 0000000..e917bbe
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.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.skywalking.e2e.dashboard;
+
+import java.util.List;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class DashboardConfigurationsMatcher extends AbstractMatcher<DashboardConfigurations> {
+    private List<DashboardConfigurationMatcher> configurations;
+
+    @Override
+    public void verify(final DashboardConfigurations configurations) {
+        DashboardConfigurationMatcher matcher = this.configurations.get(0);
+        for (int i = 0; i < configurations.size(); i++) {
+            DashboardConfiguration configuration = configurations.getConfigurations().get(i);
+            if (matcher.getName().equals(configuration.getName())) {
+                matcher.verify(configuration);
+                return;
+            }
+        }
+        throw new RuntimeException("Assertion failed!");
+    }
+}
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java
index c0756b4..bfff14c 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java
@@ -16,16 +16,17 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Data;
+import lombok.experimental.Accessors;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+@Data
+@Accessors(fluent = true)
+public class DashboardSetting {
+    private String name;
+    private TemplateType type;
+    private String configuration;
+    private boolean active;
 
-        Assert.assertEquals(30, coreModule.services().length);
-    }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java
index c0756b4..80552d2 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java
@@ -16,16 +16,12 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Data;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
-    }
-}
+@Data
+public class TemplateChangeStatus {
+    private boolean status;
+    private String message;
+}
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java
index c0756b4..ea2c9be 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java
@@ -16,16 +16,11 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Data;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
-    }
+@Data
+public class TemplateChangeStatusWrapper {
+    private TemplateChangeStatus changeStatusResult;
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java
similarity index 70%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java
index c0756b4..7893d78 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java
@@ -16,16 +16,17 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.dashboard;
 
-import org.junit.Assert;
-import org.junit.Test;
+public enum TemplateType {
+    DASHBOARD,
+    TOPOLOGY_SERVICE,
+    TOPOLOGY_INSTANCE,
+    TOPOLOGY_ENDPOINT,
+    TOPOLOGY_SERVICE_RELATION,
+    TOPOLOGY_SERVICE_INSTANCE_RELATION;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
-
-        Assert.assertEquals(30, coreModule.services().length);
+    public static TemplateType forName(String name) {
+        return Enum.valueOf(TemplateType.class, name.toUpperCase());
     }
 }
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql
index 63bddcb..864d4b6 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql
@@ -13,17 +13,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
+{
+  "query":"mutation addTemplate($settingRequest: DashboardSetting!) {
+    changeStatusResult: addTemplate(setting: $settingRequest) {
+      status: status
+      message: message
+    }
+  }",
+  "variables": {
+    "settingRequest": {
+		"name": "{name}",
+		"type": "{type}",
+		"configuration": {configuration},
+		"active": {active}
+	}
+  }
+}
 
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql
index 63bddcb..2636fb2 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql
@@ -13,17 +13,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
+{
+  "query":"mutation changeTemplate($settingRequest: DashboardSetting!) {
+    changeStatusResult: changeTemplate(setting: $settingRequest) {
+      status: status
+      message: message
+    }
+  }",
+  "variables": {
+    "settingRequest": {
+		"name": "{name}",
+		"type": "{type}",
+		"configuration": {configuration},
+		"active": {active}
+	}
+  }
+}
 
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql
index 63bddcb..380f6fd 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql
@@ -13,17 +13,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
-
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
+{
+  "query":"mutation disableTemplate($name: String!) {
+    changeStatusResult: disableTemplate(name: $name) {
+      status: status
+      message: message
+    }
+  }",
+  "variables": {
+    "name": "{name}"
+  }
+}
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql
index 63bddcb..0c11d79 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql
@@ -13,17 +13,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
-
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
+{
+  "query":"query getAllTemplates($includingDisabled: Boolean!) {
+    configurations: getAllTemplates(includingDisabled: $includingDisabled) {
+      name: name
+      type: type
+      configuration: configuration
+      activated: activated
+      disabled: disabled
+    }
+  }",
+  "variables": {
+    "includingDisabled": "{includingDisabled}"
+  }
+}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java
index 43944ed..f09b778 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java
@@ -18,13 +18,21 @@
 
 package org.apache.skywalking.e2e.storage;
 
+import java.io.IOException;
 import java.util.List;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.e2e.UIConfigurationManagementClient;
 import org.apache.skywalking.e2e.annotation.ContainerHostAndPort;
 import org.apache.skywalking.e2e.annotation.DockerCompose;
 import org.apache.skywalking.e2e.base.SkyWalkingE2E;
 import org.apache.skywalking.e2e.base.SkyWalkingTestAdapter;
 import org.apache.skywalking.e2e.common.HostAndPort;
+import org.apache.skywalking.e2e.dashboard.DashboardConfiguration;
+import org.apache.skywalking.e2e.dashboard.DashboardConfigurations;
+import org.apache.skywalking.e2e.dashboard.DashboardConfigurationsMatcher;
+import org.apache.skywalking.e2e.dashboard.DashboardSetting;
+import org.apache.skywalking.e2e.dashboard.TemplateChangeStatus;
+import org.apache.skywalking.e2e.dashboard.TemplateType;
 import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher;
 import org.apache.skywalking.e2e.metrics.Metrics;
 import org.apache.skywalking.e2e.metrics.MetricsQuery;
@@ -45,14 +53,15 @@ import org.apache.skywalking.e2e.topo.Call;
 import org.apache.skywalking.e2e.topo.ServiceInstanceTopology;
 import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyMatcher;
 import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyQuery;
-import org.apache.skywalking.e2e.topo.Topology;
 import org.apache.skywalking.e2e.topo.TopoMatcher;
 import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.topo.Topology;
 import org.apache.skywalking.e2e.trace.Trace;
 import org.apache.skywalking.e2e.trace.TracesMatcher;
 import org.apache.skywalking.e2e.trace.TracesQuery;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 import org.testcontainers.containers.DockerComposeContainer;
 
 import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
@@ -65,6 +74,7 @@ import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATIO
 import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS;
 import static org.apache.skywalking.e2e.utils.Times.now;
 import static org.apache.skywalking.e2e.utils.Yamls.load;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @Slf4j
 @SkyWalkingE2E
@@ -85,9 +95,11 @@ public class StorageE2E extends SkyWalkingTestAdapter {
     @ContainerHostAndPort(name = "provider", port = 9090)
     private HostAndPort serviceHostPort;
 
+    private UIConfigurationManagementClient graphql;
+
     @BeforeAll
     void setUp() throws Exception {
-        queryClient(swWebappHostPort);
+        graphql = new UIConfigurationManagementClient(swWebappHostPort.host(), swWebappHostPort.port());
 
         trafficController(serviceHostPort, "/users");
     }
@@ -156,6 +168,60 @@ public class StorageE2E extends SkyWalkingTestAdapter {
         verifyServiceInstanceRelationMetrics(topology.getCalls());
     }
 
+    @Test
+    void addUITemplate() throws Exception {
+        try {
+            TemplateChangeStatus templateChangeStatus = graphql.addTemplate(
+                emptySetting("test-ui-config-1").type(TemplateType.DASHBOARD)
+            );
+            LOGGER.info("add template = {}", templateChangeStatus);
+        } catch (Exception e) {
+            LOGGER.error("add ui template error.", e);
+        }
+        verifyTemplates("expected/storage/dashboardConfiguration.yml");
+    }
+
+    @Test
+    void changeTemplate() throws Exception {
+        try {
+            final String name = "test-ui-config-2";
+            assertTrue(
+                graphql.addTemplate(
+                    emptySetting(name).type(TemplateType.TOPOLOGY_SERVICE)
+                ).isStatus()
+            );
+
+            TemplateChangeStatus templateChangeStatus = graphql.changeTemplate(
+                emptySetting(name).configuration("{\"key\":\"value\"}")
+            );
+            LOGGER.info("change UITemplate = {}", templateChangeStatus);
+            assertTrue(templateChangeStatus.isStatus());
+        } catch (Exception e) {
+            LOGGER.error("add ui template error.", e);
+        }
+
+        verifyTemplates("expected/storage/dashboardConfiguration-change.yml");
+    }
+
+    @Test
+    void disableTemplate() throws IOException {
+        try {
+            final String name = "test-ui-config-3";
+            assertTrue(
+                graphql.addTemplate(
+                    emptySetting(name).type(TemplateType.DASHBOARD)
+                ).isStatus()
+            );
+
+            TemplateChangeStatus templateChangeStatus = graphql.disableTemplate(name);
+            LOGGER.info("disable template = {}", templateChangeStatus);
+            assertTrue(templateChangeStatus.isStatus());
+        } catch (Exception e) {
+            LOGGER.error("add ui template error.", e);
+        }
+        verifyTemplates("expected/storage/dashboardConfiguration-disable.yml");
+    }
+
     private Instances verifyServiceInstances(final Service service) throws Exception {
         final Instances instances = graphql.instances(
             new InstancesQuery().serviceId(service.getKey()).start(startTime).end(now())
@@ -272,4 +338,20 @@ public class StorageE2E extends SkyWalkingTestAdapter {
             }
         }
     }
+
+    private void verifyTemplates(String file) throws IOException {
+        List<DashboardConfiguration> configurations = graphql.getAllTemplates(Boolean.TRUE);
+        LOGGER.info("get all templates = {}", configurations);
+        DashboardConfigurations dashboardConfigurations = new DashboardConfigurations();
+        dashboardConfigurations.setConfigurations(configurations);
+        load(file).as(DashboardConfigurationsMatcher.class).verify(dashboardConfigurations);
+    }
+
+    private DashboardSetting emptySetting(final String name) {
+        return new DashboardSetting()
+            .name(name)
+            .active(true)
+            .configuration("{}");
+    }
+
 }
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml
index 63bddcb..636231b 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml
@@ -13,17 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
-
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
+configurations:
+  - name: test-ui-config-2
+    type: TOPOLOGY_SERVICE
+    configuration: "{}"
+    activated: true
+    disabled: false
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml
similarity index 54%
copy from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
copy to test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml
index 63bddcb..fb24303 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml
@@ -13,17 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
-
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
+configurations:
+  - name: test-ui-config-3
+    type: not null
+    configuration: not null
+    activated: true
+    disabled: true
diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml
similarity index 54%
rename from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
rename to test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml
index 63bddcb..08a091e 100644
--- a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml
+++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml
@@ -13,17 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Endpoint name grouping rules.
-# In most cased, endpoint name should be detected by agents or service mesh automatically, and aggregate the metrics based
-# on the name.
-# But, in some cases, application puts the parameter in the endpoint name, such as putting order id in the URI, like
-# /prod/ORDER123, /prod/ORDER456.
-# This grouping file provides the regex based definition capability to merge those endpoints into a group by better and
-# more meaningful aggregation metrics.
-
-grouping:
-  # Endpoint of the service would follow the following rules
-  - service-name: serviceA
-    rules:
-      - endpoint-name: /prod/{id}
-        regex: \/prod\/.+
\ No newline at end of file
+configurations:
+  - name: test-ui-config-1
+    type: not null
+    configuration: not null
+    activated: true
+    disabled: false