feat: 应用开发后端基础框架,初始提交
diff --git a/system/api/pom.xml b/system/api/pom.xml
new file mode 100644
index 0000000..5f7637f
--- /dev/null
+++ b/system/api/pom.xml
@@ -0,0 +1,111 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-api</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework System API</name>
+  <description>Supwisdom Backend Framework System API project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-system-domain</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-mvc</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java
new file mode 100644
index 0000000..d23f7c9
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminAccountController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminAccountController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java
new file mode 100644
index 0000000..9eac867
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminConfigController.java
@@ -0,0 +1,197 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.exception.ConfigException;
+import com.supwisdom.institute.backend.system.domain.service.ConfigService;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigCreateRequest;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigQueryRequest;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.vo.response.ConfigUpdateResponseData;
+
+@Api(value = "SystemAdminConfig", tags = { "SystemAdminConfig" }, description = "配置项的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/configs")
+public class AdminConfigController {
+  
+  @Autowired
+  private ConfigService configService;
+
+
+  /**
+   * @param configQueryRequest
+   * @return
+   */
+  @ApiOperation(value = "查询配置列表", notes = "查询配置列表", nickname = "systemAdminConfigQuery")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "loadAll", value = "是否加载全部", required = true, dataType = "boolean", paramType = "query", defaultValue = "false"),
+    @ApiImplicitParam(name = "pageIndex", value = "分页 - 页码", required = true, dataType = "int", paramType = "query", defaultValue = "0", example = "0"),
+    @ApiImplicitParam(name = "pageSize", value = "分页 - 每页记录数", required = true, dataType = "int", paramType = "query", defaultValue = "20", example = "20"),
+    @ApiImplicitParam(name = "mapBean[deleted]", value = "查询条件 - 删除状态 (精确)", required = false, dataType = "boolean", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[categoryCode]", value = "查询条件 - 分类代码 (精确)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[categoryName]", value = "查询条件 - 分类名称 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[name]", value = "查询条件 - 名称 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[description]", value = "查询条件 - 描述 (模糊)", required = false, dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "mapBean[configKey]", value = "查询条件 - 配置Key (精确)", required = false, dataType = "string", paramType = "query"),
+  })
+  @RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigQueryResponseData> query(ConfigQueryRequest configQueryRequest) {
+    
+    Page<Config> page = configService.selectPageList(
+        configQueryRequest.isLoadAll(),
+        configQueryRequest.getPageIndex(),
+        configQueryRequest.getPageSize(),
+        configQueryRequest.getMapBean(),
+        configQueryRequest.getOrderBy());
+
+    ConfigQueryResponseData resp = ConfigQueryResponseData.of(configQueryRequest).build(page);
+    
+    return new DefaultApiResponse<ConfigQueryResponseData>(resp);
+  }
+
+  /**
+   * @param id
+   * @return
+   */
+  @ApiOperation(value = "根据ID获取配置项", notes = "根据ID获取配置项", nickname="systemAdminConfigLoad")
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigLoadResponseData> load(
+      @PathVariable("id") String id) {
+    
+    if (id == null || id.length() == 0) {
+      throw new ConfigException().newInstance("exception.get.id.must.not.empty");
+    }
+    
+    Config config = configService.selectById(id);
+    
+    if (config == null) {
+      throw new ConfigException().newInstance("exception.get.domain.not.exist");
+    }
+
+    ConfigLoadResponseData resp = ConfigLoadResponseData.build(config);
+    
+    return new DefaultApiResponse<ConfigLoadResponseData>(resp);
+  }
+  
+  /**
+   * @param configCreateRequest
+   * @return
+   */
+  @ApiOperation(value = "创建配置项", notes = "创建配置项", nickname = "systemAdminConfigCreate")
+  @RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.CREATED)
+  @ResponseBody
+  public DefaultApiResponse<ConfigCreateResponseData> create(
+      @RequestBody ConfigCreateRequest configCreateRequest) {
+
+    // FIXME: 验证数据有效性
+
+    Config entity = configCreateRequest.getEntity();
+
+    Config ret = configService.insert(entity);
+
+    ConfigCreateResponseData resp = ConfigCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<ConfigCreateResponseData>(resp);
+  }
+
+  @ApiOperation(value = "更新配置项", notes = "更新配置项", nickname = "systemAdminConfigUpdate")
+  @RequestMapping(method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigUpdateResponseData> update(
+      @PathVariable("id") String id,
+      @RequestBody ConfigUpdateRequest configUpdateRequest) {
+
+    Config entity = configUpdateRequest.getEntity();
+
+    if (entity.getId() == null || entity.getId().length() == 0) {
+      throw new ConfigException().newInstance("exception.update.id.must.not.empty");
+    }
+
+    Config tmp = configService.selectById(entity.getId());
+    if (tmp == null) {
+      throw new ConfigException().newInstance("exception.update.domain.not.exist");
+    }
+
+    if (!tmp.getEditable().booleanValue()) {
+      throw new ConfigException().newInstance("exception.editable.can.not.update");
+    }
+
+    entity = EntityUtils.merge(tmp, entity);
+    
+//    if (tmp.getEditable().booleanValue() != entity.getEditable().booleanValue()) {
+//      throw new ConfigException().newInstance("exception.editable.can.not.update");
+//    }
+
+    entity.setEditable(true);  // 防止 可修改记录的 editable 被置为false
+
+    Config ret = configService.update(entity);
+
+    ConfigUpdateResponseData resp = ConfigUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<ConfigUpdateResponseData>(resp);
+  }
+
+  
+  /**
+   * @param categoryCode
+   * @param configKey
+   * @return
+   */
+  @ApiOperation(value = "根据 categoryCode、configKey 获取配置项", notes = "根据 categoryCode、configKey 获取配置项", nickname = "systemAdminConfigLoadByCategoryKey")
+  @RequestMapping(method = RequestMethod.GET, path = "/loadByCategoryKey", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ConfigLoadResponseData> loadByCategoryKey(
+      @RequestParam("categoryCode") String categoryCode, 
+      @RequestParam("configKey") String configKey
+      ) {
+    
+    if (categoryCode == null || categoryCode.length() == 0) {
+      throw new ConfigException().newInstance("exception.load.params.must.not.empty");
+    }
+    if (configKey == null || configKey.length() == 0) {
+      throw new ConfigException().newInstance("exception.load.params.must.not.empty");
+    }
+    
+    Config config = configService.selectByCategoryKey(categoryCode, configKey);
+    
+    if (config == null) {
+      throw new ConfigException().newInstance("exception.load.domain.not.exist");
+    }
+
+    ConfigLoadResponseData resp = ConfigLoadResponseData.build(config);
+    
+    return new DefaultApiResponse<ConfigLoadResponseData>(resp);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
new file mode 100644
index 0000000..fcb3c6a
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminFunctionController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
new file mode 100644
index 0000000..929d755
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminResourceController {
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
new file mode 100644
index 0000000..4a7a517
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+public class AdminRoleController {
+
+}
diff --git a/system/domain/pom.xml b/system/domain/pom.xml
new file mode 100644
index 0000000..8e8e2fb
--- /dev/null
+++ b/system/domain/pom.xml
@@ -0,0 +1,102 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-domain</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework System Domain</name>
+  <description>Supwisdom Backend Framework System Domain project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.supwisdom.institute</groupId>
+      <artifactId>sw-backend-common-framework</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.supwisdom.infras</groupId>
+      <artifactId>infras-data-jpa</artifactId>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java
new file mode 100644
index 0000000..16300ef
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Config.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+/**
+ * @author loie
+ */
+@Entity
+@Table(name = "TB_CONFIG")
+public class Config extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -2721844710909809785L;
+
+  /**
+   * 分类代码
+   */
+  @Getter
+  @Setter
+  @Column(name = "CATEGORY_CODE")
+  private String categoryCode;
+  
+  /**
+   * 分类名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "CATEGORY_NAME")
+  private String categoryName;
+
+  /**
+   * 名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 描述
+   */
+  @Getter
+  @Setter
+  @Column(name = "DESCRIPTION")
+  private String description;
+
+  /**
+   * 配置键
+   */
+  @Getter
+  @Setter
+  @Column(name = "CONFIG_KEY")
+  private String configKey;
+
+  /**
+   * 配置值
+   */
+  @Getter
+  @Setter
+  @Column(name = "CONFIG_VALUE")
+  private String configValue;
+
+  /**
+   * 是否可修改
+   */
+  @Getter
+  @Setter
+  @Column(name = "EDITABLE")
+  private Boolean editable;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java
new file mode 100644
index 0000000..2a9957e
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/exception/ConfigException.java
@@ -0,0 +1,12 @@
+package com.supwisdom.institute.backend.system.domain.exception;
+
+import com.supwisdom.institute.backend.common.framework.exception.BaseException;
+
+public class ConfigException extends BaseException {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8112079911386045865L;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java
new file mode 100644
index 0000000..3d6ce38
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ConfigRepository.java
@@ -0,0 +1,77 @@
+package com.supwisdom.institute.backend.system.domain.repo;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author loie
+ */
+@Repository
+public interface ConfigRepository extends BaseJpaRepository<Config> {
+  
+  public default Page<Config> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    Config probe = new Config();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCategoryCode(MapBeanUtils.getString(mapBean, "categoryCode"));
+      probe.setCategoryName(MapBeanUtils.getString(mapBean, "categoryName"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setDescription(MapBeanUtils.getString(mapBean, "description"));
+      probe.setConfigKey(MapBeanUtils.getString(mapBean, "configKey"));
+      probe.setEditable(MapBeanUtils.getBoolean(mapBean, "editable"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryCode", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryName", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("description", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("configKey", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("editable", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+    
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Config> example = Example.of(probe, matcher);
+    
+    Page<Config> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+
+  public default Config selectByCategoryKey(String categoryCode, String configKey) {
+    Config probe = new Config();
+    
+    probe.setDeleted(false);
+    probe.setCategoryCode(categoryCode);
+    probe.setConfigKey(configKey);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("categoryCode", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("configKey", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+    
+    Example<Config> example = Example.of(probe, matcher);
+    
+    Optional<Config> config = this.findOne(example);
+    
+    return config.isPresent() ? config.get() : null;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java
new file mode 100644
index 0000000..858da54
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ConfigService.java
@@ -0,0 +1,26 @@
+package com.supwisdom.institute.backend.system.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.repo.ConfigRepository;
+
+@Service
+public class ConfigService extends ABaseService<Config, ConfigRepository> {
+  
+  @Autowired
+  private ConfigRepository configRepository;
+
+  @Override
+  public ConfigRepository getRepo() {
+    return configRepository;
+  }
+
+  public Config selectByCategoryKey(String categoryCode, String configKey) {
+    
+    return configRepository.selectByCategoryKey(categoryCode, configKey);
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
new file mode 100644
index 0000000..8c741fe
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigCreateRequest.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+/**
+ * @author loie
+ */
+public class ConfigCreateRequest extends Config implements IApiCreateRequest {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8380208871984763567L;
+
+  public Config getEntity() {
+    return EntityUtils.copy(this, new Config());
+  }
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
new file mode 100644
index 0000000..e83083b
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigQueryRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class ConfigQueryRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -1033044092932525382L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
new file mode 100644
index 0000000..6f7e1a5
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/request/ConfigUpdateRequest.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.system.domain.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigUpdateRequest extends Config implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6002556449210326472L;
+
+  @Getter
+  @Setter
+  private String id;
+  
+  
+  public Config getEntity() {
+    return EntityUtils.copy(this, new Config());
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
new file mode 100644
index 0000000..a14a607
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigCreateResponseData.java
@@ -0,0 +1,32 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigCreateResponseData extends Config implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -2300091307366254182L;
+  
+  @Getter
+  @Setter
+  private String id;
+
+  private ConfigCreateResponseData() {
+    
+  }
+  
+  public static ConfigCreateResponseData build(Config entity) {
+    ConfigCreateResponseData configCreateResponse = new ConfigCreateResponseData();
+    return EntityUtils.copy(entity, configCreateResponse);
+  }
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
new file mode 100644
index 0000000..a32312d
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigLoadResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigLoadResponseData extends Config implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -579946566129915779L;
+
+  @Getter
+  @Setter
+  private String id;
+  
+  
+  private ConfigLoadResponseData() {
+    
+  }
+  
+  public static ConfigLoadResponseData build(Config entity) {
+    ConfigLoadResponseData configCreateResponse = new ConfigLoadResponseData();
+    return EntityUtils.copy(entity, configCreateResponse);
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
new file mode 100644
index 0000000..906d681
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigQueryResponseData.java
@@ -0,0 +1,83 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+import com.supwisdom.institute.backend.system.domain.vo.request.ConfigQueryRequest;
+
+/**
+ * @author loie
+ */
+public class ConfigQueryResponseData implements IApiQueryResponseData<Config> {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3188467441502226095L;
+  
+//  private ConfigQueryResponseData() {
+//  }
+  
+  public ConfigQueryResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static ConfigQueryResponseData of(ConfigQueryRequest configQueryRequest) {
+    ConfigQueryResponseData configQueryResponse = new ConfigQueryResponseData(
+        configQueryRequest.isLoadAll(), 
+        configQueryRequest.getPageIndex(), 
+        configQueryRequest.getPageSize(), 
+        configQueryRequest.getMapBean(), 
+        configQueryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public ConfigQueryResponseData build(Page<Config> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<Config> items;
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
new file mode 100644
index 0000000..556307b
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigRemoveResponseData.java
@@ -0,0 +1,36 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.Id;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+/**
+ * @author loie
+ */
+public class ConfigRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8510464738198696332L;
+
+  @Getter
+  @Setter
+  @Id
+  private String id;
+
+  private ConfigRemoveResponseData() {
+    
+  }
+  
+  public static ConfigRemoveResponseData build(Config entity) {
+    ConfigRemoveResponseData configRemoveResponse = new ConfigRemoveResponseData();
+    return EntityUtils.copy(entity, configRemoveResponse);
+  }
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
new file mode 100644
index 0000000..51ca051
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/vo/response/ConfigUpdateResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.domain.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ConfigUpdateResponseData extends Config implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 2798387429543859170L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ConfigUpdateResponseData() {
+    
+  }
+  
+  public static ConfigUpdateResponseData build(Config entity) {
+    ConfigUpdateResponseData configUpdateResponse = new ConfigUpdateResponseData();
+    return EntityUtils.copy(entity, configUpdateResponse);
+  }
+  
+}
diff --git a/system/pom.xml b/system/pom.xml
new file mode 100644
index 0000000..d80ee43
--- /dev/null
+++ b/system/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>com.supwisdom.institute</groupId>
+    <artifactId>sw-backend-parent</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>com.supwisdom.institute</groupId>
+  <artifactId>sw-backend-system-aggregator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>Supwisdom Backend Framework System Aggregator</name>
+  <description>Supwisdom Backend Framework System Aggregator project</description>
+
+  <modules>
+    <module>domain</module>
+    <module>api</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>