refactor: 重命名项目目录,system -> base
diff --git a/base/domain/.gitignore b/base/domain/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/base/domain/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/base/domain/pom.xml b/base/domain/pom.xml
new file mode 100644
index 0000000..26580ba
--- /dev/null
+++ b/base/domain/pom.xml
@@ -0,0 +1,99 @@
+<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-base-domain</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Supwisdom Backend Framework Base Domain</name>
+  <description>Supwisdom Backend Framework Base Domain project</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </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.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/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/.gitkeep b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/.gitkeep
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Account.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Account.java
new file mode 100644
index 0000000..9e05174
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Account.java
@@ -0,0 +1,164 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ACCOUNT")
+public class Account extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 7955624268022038897L;
+  
+  public static final String STATUS_ENABLED = "1";
+  public static final String STATUS_DISABLED = "0";
+  
+
+  /**
+   * 用户名
+   */
+  @Column(name = "USERNAME", unique = true)
+  private String username;
+  
+  /**
+   * 密码
+   */
+  @Column(name = "PASSWORD")
+  private String password;
+
+  /**
+   * 是否可用,1 可用,0 不可用,默认:1
+   */
+  @Column(name = "ENABLED")
+  private Boolean enabled;
+  /**
+   * 账号未过期,1 未过期,0 过期,默认:1
+   */
+  @Column(name = "ACCOUNT_NON_EXPIRED")
+  private Boolean accountNonExpired;
+  /**
+   * 账号未锁定,1 未锁定,0 锁定,默认:1
+   */
+  @Column(name = "ACCOUNT_NON_LOCKED")
+  private Boolean accountNonLocked;
+  /**
+   * 密码未过期,1 未过期,0 过期,默认:1
+   */
+  @Column(name = "CREDENTIALS_NON_EXPIRED")
+  private Boolean credentialsNonExpired;
+
+  /**
+   * 姓名
+   */
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Column(name = "MEMO")
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Column(name = "STATUS")
+  private String status;
+
+  /**
+   * 登录手机
+   */
+  @Column(name = "MOBILE", nullable = true)
+  private String mobile;
+  /**
+   * 登录邮箱
+   */
+  @Column(name = "EMAIL", nullable = true)
+  private String email;
+
+  public String getUsername() {
+    return username;
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+
+  public void setPassword(String password) {
+    this.password = password;
+  }
+
+  public Boolean getEnabled() {
+    return enabled;
+  }
+
+  public void setEnabled(Boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  public Boolean getAccountNonExpired() {
+    return accountNonExpired;
+  }
+
+  public void setAccountNonExpired(Boolean accountNonExpired) {
+    this.accountNonExpired = accountNonExpired;
+  }
+
+  public Boolean getAccountNonLocked() {
+    return accountNonLocked;
+  }
+
+  public void setAccountNonLocked(Boolean accountNonLocked) {
+    this.accountNonLocked = accountNonLocked;
+  }
+
+  public Boolean getCredentialsNonExpired() {
+    return credentialsNonExpired;
+  }
+
+  public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
+    this.credentialsNonExpired = credentialsNonExpired;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getMobile() {
+    return mobile;
+  }
+
+  public void setMobile(String mobile) {
+    this.mobile = mobile;
+  }
+
+  public String getEmail() {
+    return email;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountGroup.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountGroup.java
new file mode 100644
index 0000000..318d373
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountGroup.java
@@ -0,0 +1,46 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ACCOUNT_GROUP")
+public class AccountGroup extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -4239845385965871983L;
+
+  /**
+   * 帐号ID
+   */
+  @Column(name = "ACCOUNT_ID")
+  private String accountId;
+
+  /**
+   * 用户组ID
+   */
+  @Column(name = "GROUP_ID")
+  private String groupId;
+
+  public String getAccountId() {
+    return accountId;
+  }
+
+  public void setAccountId(String accountId) {
+    this.accountId = accountId;
+  }
+
+  public String getGroupId() {
+    return groupId;
+  }
+
+  public void setGroupId(String groupId) {
+    this.groupId = groupId;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountRole.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountRole.java
new file mode 100644
index 0000000..4a834b0
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/AccountRole.java
@@ -0,0 +1,46 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ACCOUNT_ROLE")
+public class AccountRole extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6158470486381850942L;
+
+  /**
+   * 帐号ID
+   */
+  @Column(name = "ACCOUNT_ID")
+  private String accountId;
+
+  /**
+   * 角色ID
+   */
+  @Column(name = "ROLE_ID")
+  private String roleId;
+
+  public String getAccountId() {
+    return accountId;
+  }
+
+  public void setAccountId(String accountId) {
+    this.accountId = accountId;
+  }
+
+  public String getRoleId() {
+    return roleId;
+  }
+
+  public void setRoleId(String roleId) {
+    this.roleId = roleId;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Config.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Config.java
new file mode 100644
index 0000000..ee78348
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Config.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.base.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/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Group.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Group.java
new file mode 100644
index 0000000..87eaf2e
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Group.java
@@ -0,0 +1,74 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity(name = "Group_")
+@Table(name = "TB_U_GROUP")
+public class Group extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4260326816456622523L;
+
+  /**
+   * 代码
+   */
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Column(name = "MEMO")
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Column(name = "STATUS")
+  private String status;
+
+  public String getCode() {
+    return code;
+  }
+
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getMemo() {
+    return memo;
+  }
+
+  public void setMemo(String memo) {
+    this.memo = memo;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/GroupRole.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/GroupRole.java
new file mode 100644
index 0000000..be96211
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/GroupRole.java
@@ -0,0 +1,46 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_GROUP_ROLE")
+public class GroupRole extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3141266845902556712L;
+
+  /**
+   * 用户组ID
+   */
+  @Column(name = "GROUP_ID")
+  private String groupId;
+
+  /**
+   * 角色ID
+   */
+  @Column(name = "ROLE_ID")
+  private String roleId;
+
+  public String getGroupId() {
+    return groupId;
+  }
+
+  public void setGroupId(String groupId) {
+    this.groupId = groupId;
+  }
+
+  public String getRoleId() {
+    return roleId;
+  }
+
+  public void setRoleId(String roleId) {
+    this.roleId = roleId;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Permission.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Permission.java
new file mode 100644
index 0000000..0d7dbd0
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Permission.java
@@ -0,0 +1,177 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_PERMISSION")
+public class Permission extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -8834200833972243635L;
+  
+  public static final String ROOT_PARENT_ID = "0";
+
+  public static final String TYPE_MENU = "2";
+  public static final String TYPE_OPERATION = "3";
+
+  /**
+   * 代码
+   */
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Column(name = "MEMO", nullable = true)
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Column(name = "STATUS")
+  private String status;
+
+  /**
+   * 类型(1 应用,2 菜单,3 操作)
+   */
+  @Column(name = "TYPE_")
+  private String type;
+
+  /**
+   * URL地址
+   */
+  @Column(name = "URL", nullable = true)
+  private String url;
+
+  /**
+   * 父级ID
+   */
+  @Column(name = "PARENT_ID")
+  private String parentId;
+
+  /**
+   * 排序
+   */
+  @Column(name = "ORDER_")
+  private Integer order;
+
+  /**
+   * 层次
+   */
+  @Column(name = "LEVEL_")
+  private Integer level;
+
+  /**
+   * 左序
+   */
+  @Column(name = "LFT")
+  private Integer lft;
+
+  /**
+   * 右序
+   */
+  @Column(name = "RGT")
+  private Integer rgt;
+
+  public String getCode() {
+    return code;
+  }
+
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getMemo() {
+    return memo;
+  }
+
+  public void setMemo(String memo) {
+    this.memo = memo;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+  public String getParentId() {
+    return parentId;
+  }
+
+  public void setParentId(String parentId) {
+    this.parentId = parentId;
+  }
+
+  public Integer getOrder() {
+    return order;
+  }
+
+  public void setOrder(Integer order) {
+    this.order = order;
+  }
+
+  public Integer getLevel() {
+    return level;
+  }
+
+  public void setLevel(Integer level) {
+    this.level = level;
+  }
+
+  public Integer getLft() {
+    return lft;
+  }
+
+  public void setLft(Integer lft) {
+    this.lft = lft;
+  }
+
+  public Integer getRgt() {
+    return rgt;
+  }
+
+  public void setRgt(Integer rgt) {
+    this.rgt = rgt;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Resource.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Resource.java
new file mode 100644
index 0000000..7b3a08c
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Resource.java
@@ -0,0 +1,61 @@
+package com.supwisdom.institute.backend.base.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;
+
+@Entity
+@Table(name = "TB_U_RESOURCE")
+public class Resource extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4288268877209267453L;
+
+  /**
+   * 代码
+   */
+  @Getter
+  @Setter
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Getter
+  @Setter
+  @Column(name = "MEMO", nullable = true)
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Getter
+  @Setter
+  @Column(name = "STATUS")
+  private String status;
+
+  /**
+   * URL地址
+   */
+  @Getter
+  @Setter
+  @Column(name = "URL", nullable = true)
+  private String url;
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Role.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Role.java
new file mode 100644
index 0000000..0714133
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/Role.java
@@ -0,0 +1,74 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ROLE")
+public class Role extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5470129732727732514L;
+
+  /**
+   * 代码
+   */
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Column(name = "MEMO")
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Column(name = "STATUS")
+  private String status;
+
+  public String getCode() {
+    return code;
+  }
+
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getMemo() {
+    return memo;
+  }
+
+  public void setMemo(String memo) {
+    this.memo = memo;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/RolePermission.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/RolePermission.java
new file mode 100644
index 0000000..df8a031
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/entity/RolePermission.java
@@ -0,0 +1,46 @@
+package com.supwisdom.institute.backend.base.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ROLE_PERMISSION")
+public class RolePermission extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5293251541687343949L;
+
+  /**
+   * 角色ID
+   */
+  @Column(name = "ROLE_ID")
+  private String roleId;
+
+  /**
+   * 权限ID
+   */
+  @Column(name = "PERMISSION_ID")
+  private String permissionId;
+
+  public String getRoleId() {
+    return roleId;
+  }
+
+  public void setRoleId(String roleId) {
+    this.roleId = roleId;
+  }
+
+  public String getPermissionId() {
+    return permissionId;
+  }
+
+  public void setPermissionId(String permissionId) {
+    this.permissionId = permissionId;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/.gitkeep b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/.gitkeep
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/ConfigException.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/ConfigException.java
new file mode 100644
index 0000000..77fee05
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/exception/ConfigException.java
@@ -0,0 +1,12 @@
+package com.supwisdom.institute.backend.base.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/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/.gitkeep b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/.gitkeep
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/PermissionTreeNode.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/PermissionTreeNode.java
new file mode 100644
index 0000000..233de5f
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/model/PermissionTreeNode.java
@@ -0,0 +1,24 @@
+package com.supwisdom.institute.backend.base.domain.model;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import com.supwisdom.institute.backend.base.domain.entity.Permission;
+import com.supwisdom.institute.backend.common.framework.model.IModel;
+
+@ToString
+public class PermissionTreeNode extends Permission implements IModel {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 6984458902464386215L;
+  
+  @Getter
+  @Setter
+  List<PermissionTreeNode> children;
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/.gitkeep b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/.gitkeep
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountGroupRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountGroupRepository.java
new file mode 100644
index 0000000..be61930
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountGroupRepository.java
@@ -0,0 +1,191 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+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.base.domain.entity.Account;
+import com.supwisdom.institute.backend.base.domain.entity.AccountGroup;
+import com.supwisdom.institute.backend.base.domain.entity.Group;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface AccountGroupRepository extends BaseJpaRepository<AccountGroup> {
+
+  public default Page<AccountGroup> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    AccountGroup probe = new AccountGroup();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountGroup> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<AccountGroup> selectAccountGroups(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountGroup probe = new AccountGroup();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountGroup> page = this.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateAccountGroups(Account account, List<AccountGroup> accountGroups) {
+
+    List<AccountGroup> existAccountGroups = this.selectListByAccountId(account.getId());
+
+    Map<String, AccountGroup> existMapAccountGroups = new LinkedHashMap<String, AccountGroup>();
+    for (AccountGroup accountGroup : existAccountGroups) {
+      String k = String.format("%s", accountGroup.getGroupId());
+      existMapAccountGroups.put(k, accountGroup);
+    }
+
+    for (AccountGroup accountGroup : accountGroups) {
+      String k = String.format("%s", accountGroup.getGroupId());
+
+      if (existMapAccountGroups.containsKey(k)) {
+        existMapAccountGroups.remove(k);
+      } else {
+        accountGroup.setCompanyId(account.getCompanyId());
+        accountGroup.setAccountId(account.getId());
+
+        this.insert(accountGroup);
+      }
+    }
+
+    for (AccountGroup accountGroup : existMapAccountGroups.values()) {
+      this.deleteById(accountGroup.getId());
+    }
+  }
+
+  public default List<AccountGroup> selectListByAccountId(String accountId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setAccountId(accountId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    List<AccountGroup> accountGroups = this.findAll(example);
+
+    return accountGroups;
+  }
+
+  public default void relateGroupAccounts(Group group, List<AccountGroup> accountGroups) {
+
+    List<AccountGroup> existGroupAccounts = this.selectListByGroupId(group.getId());
+
+    Map<String, AccountGroup> existMapGroupAccounts = new LinkedHashMap<String, AccountGroup>();
+    for (AccountGroup accountGroup : existGroupAccounts) {
+      String k = String.format("%s", accountGroup.getAccountId());
+      existMapGroupAccounts.put(k, accountGroup);
+    }
+
+    for (AccountGroup accountGroup : accountGroups) {
+      String k = String.format("%s", accountGroup.getAccountId());
+
+      if (existMapGroupAccounts.containsKey(k)) {
+        existMapGroupAccounts.remove(k);
+      } else {
+        accountGroup.setCompanyId(group.getCompanyId());
+        accountGroup.setGroupId(group.getId());
+
+        this.insert(accountGroup);
+      }
+    }
+
+    for (AccountGroup accountGroup : existMapGroupAccounts.values()) {
+      this.deleteById(accountGroup.getId());
+    }
+  }
+
+  public default List<AccountGroup> selectListByGroupId(String groupId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    List<AccountGroup> accountGroups = this.findAll(example);
+
+    return accountGroups;
+  }
+  
+  public default AccountGroup selectOneByAccountGroup(String accountId, String groupId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setAccountId(accountId);
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        ;
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+    
+    Optional<AccountGroup> o = this.findOne(example);
+    
+    return o.isPresent() ? o.get() : null;
+  }
+
+  public default void addAccountGroup(String accountId, String groupId) {
+    
+    AccountGroup accountGroup = this.selectOneByAccountGroup(accountId, groupId);
+    
+    if (accountGroup == null) {
+      accountGroup = new AccountGroup();
+      //accountGroup.setCompanyId(companyId);
+      accountGroup.setAccountId(accountId);
+      accountGroup.setGroupId(groupId);
+      
+      this.insert(accountGroup);
+    }
+  }
+
+  public default void removeAccountGroup(String accountId, String groupId) {
+    
+    AccountGroup accountGroup = this.selectOneByAccountGroup(accountId, groupId);
+    
+    if (accountGroup != null) {
+      this.deleteById(accountGroup.getId());
+    }
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRepository.java
new file mode 100644
index 0000000..e4d9e07
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRepository.java
@@ -0,0 +1,199 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.StringUtils;
+
+import com.supwisdom.institute.backend.base.domain.entity.Account;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface AccountRepository extends BaseJpaRepository<Account> {
+  
+//  public default Page<Account> selectPageList(int pageIndex, int pageSize, Account probe) {
+//    
+//    ExampleMatcher matcher = ExampleMatcher.matching()
+//        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+//    
+//    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+//    Example<Account> example = Example.of(probe, matcher);
+//    
+//    Page<Account> page = this.findAll(example, pageRequest);
+//    
+//    return page;
+//  }
+  
+  
+  @Override
+  public default Specification<Account> convertToSpec(Map<String, Object> mapBean) {
+    
+    Specification<Account> spec = new Specification<Account>() {
+
+      /**
+       * 
+       */
+      private static final long serialVersionUID = 9071470982419099273L;
+
+      @Override
+      public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+        List<Predicate> predicates = new ArrayList<>();
+        
+        if (mapBean != null) {
+
+          if (MapBeanUtils.getBoolean(mapBean, "deleted") != null) {
+            predicates.add(criteriaBuilder.equal(root.get("deleted"), MapBeanUtils.getBoolean(mapBean, "deleted")));
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "username"))) {
+            predicates.add(criteriaBuilder.like(root.get("username"), "%" + MapBeanUtils.getString(mapBean, "username") + "%"));
+          }
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "name"))) {
+            predicates.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "name") + "%"));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "status"))) {
+            predicates.add(criteriaBuilder.equal(root.get("status"), MapBeanUtils.getString(mapBean, "status")));
+          }
+          
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeBegin"))) {
+//            String grantTimeBegin = MapBeanUtils.getString(mapBean, "grantTimeBegin");
+//            Date d = DateUtil.parseDate(grantTimeBegin+" 00:00:00", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+//
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeEnd"))) {
+//            String grantTimeEnd = MapBeanUtils.getString(mapBean, "grantTimeEnd");
+//            Date d = DateUtil.parseDate(grantTimeEnd+" 23:59:59", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+
+          List<Predicate> predicatesKeyword = new ArrayList<>();
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "keyword"))) {
+            predicatesKeyword.add(criteriaBuilder.like(root.get("username"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("memo"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            
+            predicates.add(criteriaBuilder.or(predicatesKeyword.toArray(new Predicate[predicatesKeyword.size()])));
+          }
+        }
+        
+        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+      }
+      
+    };
+    
+    return spec;
+  }
+  
+  
+//  @Override
+//  public default Page<Account> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+//    if (loadAll) {
+//      pageIndex = 0;
+//      pageSize = Integer.MAX_VALUE;
+//    }
+//    
+//    Account probe = new Account();
+//    if (mapBean != null) {
+//      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+//      probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
+//      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+//      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+//    }
+//    
+//    ExampleMatcher matcher = ExampleMatcher.matching()
+//        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+//        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+//    
+//    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+//    Example<Account> example = Example.of(probe, matcher);
+//    
+//    Page<Account> page = this.findAll(example, pageRequest);
+//    
+//    return page;
+//  }
+  
+  /*
+  public default User selectById(String id) {
+    
+    try {
+      Optional<User> entity = this.findById(id);
+      
+      return entity.get();
+    } catch(RuntimeException e) {
+      System.out.println("RuntimeException:"+e.getMessage());
+    } catch(Exception e) {
+      System.out.println("Exception:"+e.getMessage());
+    }
+    
+    return null;
+  }
+  
+  public default User insert(User entity) {
+    
+    if (entity.getCompanyId() == null || entity.getCompanyId().isEmpty()) {
+      entity.setCompanyId("1");
+    }
+    
+    entity.setDeleted(false);
+    //entity.setAddAccount(AuthUtil.getRemoteUser());
+    entity.setAddTime(Calendar.getInstance().getTime());
+    
+    User e = this.save(entity);
+    
+    return e;
+  }
+  
+  public default User update(User entity) {
+    
+    //entity.setEditAccount(AuthUtil.getRemoteUser());
+    entity.setEditTime(Calendar.getInstance().getTime());
+    
+    User e = this.save(entity);
+    
+    return e;
+  }
+  */
+  
+  public default Account selectByUsername(String username) {
+    Account probe = new Account();
+    probe.setUsername(username);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Account> example = Example.of(probe, matcher);
+    
+    Optional<Account> u = this.findOne(example);
+    
+    if (u.isPresent()) {
+      return u.get();
+    }
+    
+    return null;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRoleRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRoleRepository.java
new file mode 100644
index 0000000..503f3b5
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/AccountRoleRepository.java
@@ -0,0 +1,191 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+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.base.domain.entity.Account;
+import com.supwisdom.institute.backend.base.domain.entity.AccountRole;
+import com.supwisdom.institute.backend.base.domain.entity.Role;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface AccountRoleRepository extends BaseJpaRepository<AccountRole> {
+
+  public default Page<AccountRole> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountRole probe = new AccountRole();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    Page<AccountRole> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<AccountRole> selectAccountRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountRole probe = new AccountRole();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountRole> page = this.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateAccountRoles(Account account, List<AccountRole> accountRoles) {
+
+    List<AccountRole> existAccountRoles = this.selectListByAccountId(account.getId());
+
+    Map<String, AccountRole> existMapAccountRoles = new LinkedHashMap<String, AccountRole>();
+    for (AccountRole accountRole : existAccountRoles) {
+      String k = String.format("%s", accountRole.getRoleId());
+      existMapAccountRoles.put(k, accountRole);
+    }
+
+    for (AccountRole accountRole : accountRoles) {
+      String k = String.format("%s", accountRole.getRoleId());
+
+      if (existMapAccountRoles.containsKey(k)) {
+        existMapAccountRoles.remove(k);
+      } else {
+        accountRole.setCompanyId(account.getCompanyId());
+        accountRole.setAccountId(account.getId());
+
+        this.insert(accountRole);
+      }
+    }
+
+    for (AccountRole accountRole : existMapAccountRoles.values()) {
+      this.deleteById(accountRole.getId());
+    }
+  }
+
+  public default List<AccountRole> selectListByAccountId(String accountId) {
+
+    AccountRole probe = new AccountRole();
+    probe.setAccountId(accountId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("accountId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    List<AccountRole> accountRoles = this.findAll(example);
+
+    return accountRoles;
+  }
+
+  public default void relateRoleAccounts(Role role, List<AccountRole> accountRoles) {
+
+    List<AccountRole> existRoleAccounts = this.selectListByRoleId(role.getId());
+
+    Map<String, AccountRole> existMapRoleAccounts = new LinkedHashMap<String, AccountRole>();
+    for (AccountRole accountRole : existRoleAccounts) {
+      String k = String.format("%s", accountRole.getAccountId());
+      existMapRoleAccounts.put(k, accountRole);
+    }
+
+    for (AccountRole accountRole : accountRoles) {
+      String k = String.format("%s", accountRole.getAccountId());
+
+      if (existMapRoleAccounts.containsKey(k)) {
+        existMapRoleAccounts.remove(k);
+      } else {
+        accountRole.setCompanyId(role.getCompanyId());
+        accountRole.setRoleId(role.getId());
+
+        this.insert(accountRole);
+      }
+    }
+
+    for (AccountRole accountRole : existMapRoleAccounts.values()) {
+      this.deleteById(accountRole.getId());
+    }
+  }
+
+  public default List<AccountRole> selectListByRoleId(String roleId) {
+
+    AccountRole probe = new AccountRole();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("roleId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    List<AccountRole> accountRoles = this.findAll(example);
+
+    return accountRoles;
+  }
+  
+  public default AccountRole selectOneByAccountRole(String accountId, String roleId) {
+
+    AccountRole probe = new AccountRole();
+    probe.setAccountId(accountId);
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        ;
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+    
+    Optional<AccountRole> o = this.findOne(example);
+    
+    return o.isPresent() ? o.get() : null;
+  }
+
+  public default void addAccountRole(String accountId, String roleId) {
+
+    AccountRole accountRole = this.selectOneByAccountRole(accountId, roleId);
+    
+    if (accountRole == null) {
+      accountRole = new AccountRole();
+      //accountRole.setCompanyId(companyId);
+      accountRole.setAccountId(accountId);
+      accountRole.setRoleId(roleId);
+      
+      this.insert(accountRole);
+    }
+  }
+
+  public default void removeAccountRole(String accountId, String roleId) {
+
+    AccountRole accountRole = this.selectOneByAccountRole(accountId, roleId);
+    
+    if (accountRole != null) {
+      this.deleteById(accountRole.getId());
+    }
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ConfigRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ConfigRepository.java
new file mode 100644
index 0000000..052115e
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ConfigRepository.java
@@ -0,0 +1,77 @@
+package com.supwisdom.institute.backend.base.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.base.domain.entity.Config;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+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/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRepository.java
new file mode 100644
index 0000000..9db0e26
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRepository.java
@@ -0,0 +1,49 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.Map;
+
+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.base.domain.entity.Group;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface GroupRepository extends BaseJpaRepository<Group> {
+
+  @Override
+  public default Page<Group> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Group probe = new Group();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Group> example = Example.of(probe, matcher);
+    
+    Page<Group> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+  
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRoleRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRoleRepository.java
new file mode 100644
index 0000000..35bd4d5
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/GroupRoleRepository.java
@@ -0,0 +1,191 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+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.base.domain.entity.Group;
+import com.supwisdom.institute.backend.base.domain.entity.GroupRole;
+import com.supwisdom.institute.backend.base.domain.entity.Role;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface GroupRoleRepository extends BaseJpaRepository<GroupRole> {
+
+  public default Page<GroupRole> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    Page<GroupRole> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<GroupRole> selectGroupRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupRole> page = this.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateGroupRoles(Group group, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existGroupRoles = this.selectListByGroupId(group.getId());
+
+    Map<String, GroupRole> existMapGroupRoles = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existGroupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+      existMapGroupRoles.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+
+      if (existMapGroupRoles.containsKey(k)) {
+        existMapGroupRoles.remove(k);
+      } else {
+        groupRole.setCompanyId(group.getCompanyId());
+        groupRole.setGroupId(group.getId());
+
+        this.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapGroupRoles.values()) {
+      this.deleteById(groupRole.getId());
+    }
+  }
+
+  public default List<GroupRole> selectListByGroupId(String groupId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("groupId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = this.findAll(example);
+
+    return groupRoles;
+  }
+
+
+  public default void relateRoleGroups(Role role, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existRoleGroups = this.selectListByRoleId(role.getCode());
+
+    Map<String, GroupRole> existMapRoleGroups = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existRoleGroups) {
+      String k = String.format("%s", groupRole.getGroupId());
+      existMapRoleGroups.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getGroupId());
+
+      if (existMapRoleGroups.containsKey(k)) {
+        existMapRoleGroups.remove(k);
+      } else {
+        groupRole.setCompanyId(role.getCompanyId());
+        groupRole.setRoleId(role.getId());
+
+        this.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapRoleGroups.values()) {
+      this.deleteById(groupRole.getId());
+    }
+  }
+
+  public default List<GroupRole> selectListByRoleId(String roleId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = this.findAll(example);
+
+    return groupRoles;
+  }
+
+  public default GroupRole selectOneByGroupRole(String groupId, String roleId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setGroupId(groupId);
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        ;
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+    
+    Optional<GroupRole> o = this.findOne(example);
+    
+    return o.isPresent() ? o.get() : null;
+  }
+
+  public default void addGroupRole(String groupId, String roleId) {
+
+    GroupRole groupRole = this.selectOneByGroupRole(groupId, roleId);
+    
+    if (groupRole == null) {
+      groupRole = new GroupRole();
+      //groupRole.setCompanyId(companyId);
+      groupRole.setGroupId(groupId);
+      groupRole.setRoleId(roleId);
+      
+      this.insert(groupRole);
+    }
+  }
+
+  public default void removeGroupRole(String groupId, String roleId) {
+
+    GroupRole groupRole = this.selectOneByGroupRole(groupId, roleId);
+    
+    if (groupRole != null) {
+      this.deleteById(groupRole.getId());
+    }
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/PermissionRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/PermissionRepository.java
new file mode 100644
index 0000000..e7e7940
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/PermissionRepository.java
@@ -0,0 +1,409 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.transaction.Transactional;
+
+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.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.StringUtils;
+
+import com.supwisdom.institute.backend.base.domain.entity.Permission;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+@Transactional
+public interface PermissionRepository extends BaseJpaRepository<Permission> {
+  
+
+  @Override
+  public default Specification<Permission> convertToSpec(Map<String, Object> mapBean) {
+    
+    Specification<Permission> spec = new Specification<Permission>() {
+
+      /**
+       * 
+       */
+      private static final long serialVersionUID = 9071470982419099273L;
+
+      @Override
+      public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+        List<Predicate> predicates = new ArrayList<>();
+        
+        if (mapBean != null) {
+
+          if (MapBeanUtils.getBoolean(mapBean, "deleted") != null) {
+            predicates.add(criteriaBuilder.equal(root.get("deleted"), MapBeanUtils.getBoolean(mapBean, "deleted")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "code"))) {
+            predicates.add(criteriaBuilder.like(root.get("code"), "%" + MapBeanUtils.getString(mapBean, "code") + "%"));
+          }
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "name"))) {
+            predicates.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "name") + "%"));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "status"))) {
+            predicates.add(criteriaBuilder.equal(root.get("status"), MapBeanUtils.getString(mapBean, "status")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "type"))) {
+            predicates.add(criteriaBuilder.equal(root.get("type"), MapBeanUtils.getString(mapBean, "type")));
+          }
+          
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "url"))) {
+            predicates.add(criteriaBuilder.like(root.get("url"), "%" + MapBeanUtils.getString(mapBean, "url") + "%"));
+          }
+
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "parentId"))) {
+            predicates.add(criteriaBuilder.equal(root.get("parentId"), MapBeanUtils.getString(mapBean, "parentId")));
+          }
+
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeBegin"))) {
+//            String grantTimeBegin = MapBeanUtils.getString(mapBean, "grantTimeBegin");
+//            Date d = DateUtil.parseDate(grantTimeBegin+" 00:00:00", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+//
+//          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "grantTimeEnd"))) {
+//            String grantTimeEnd = MapBeanUtils.getString(mapBean, "grantTimeEnd");
+//            Date d = DateUtil.parseDate(grantTimeEnd+" 23:59:59", "yyyy-MM-dd HH:mm:ss");
+//            
+//            if (d != null) {
+//              predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("grantTime"), d));
+//            }
+//          }
+
+          List<Predicate> predicatesKeyword = new ArrayList<>();
+          if (!StringUtils.isEmpty(MapBeanUtils.getString(mapBean, "keyword"))) {
+            predicatesKeyword.add(criteriaBuilder.like(root.get("username"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("name"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            predicatesKeyword.add(criteriaBuilder.like(root.get("memo"), "%" + MapBeanUtils.getString(mapBean, "keyword") + "%"));
+            
+            predicates.add(criteriaBuilder.or(predicatesKeyword.toArray(new Predicate[predicatesKeyword.size()])));
+          }
+        }
+        
+        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+      }
+      
+    };
+    
+    return spec;
+  }
+  
+  @Override
+  public default Page<Permission> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Permission probe = new Permission();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+      probe.setType(MapBeanUtils.getString(mapBean, "type"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("type", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Permission> example = Example.of(probe, matcher);
+    
+    Page<Permission> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+  
+  
+  
+  @Query(value = "select max(p.rgt) from Permission p")
+  public int selectMaxRgt();
+  
+  @Query(value = "select p from Permission p where p.lft>:lft and p.rgt<:rgt order by p.lft")
+  public List<Permission> selectBetweenLftRgt(@Param("lft") int lft, @Param("rgt") int rgt);
+  
+  @Modifying
+  @Query(value = "update TB_U_PERMISSION "
+      + "set "
+      + "  LFT = (case when LFT >= :rgt then LFT + :offset else LFT end), "
+      + "  RGT = RGT + :offset "
+      + "where RGT >= :rgt", nativeQuery = true)
+  public int updateLftRgtWhenInsert(@Param("rgt") int rgt, @Param("offset") int offset);
+
+  @Modifying
+  @Query(value = "update TB_U_PERMISSION "
+      + "set "
+      + "  LFT = (case when LFT >= :rgt then LFT - :offset else LFT end), "
+      + "  RGT = RGT - :offset "
+      + "where RGT >= :rgt", nativeQuery = true)
+  public int updateLftRgtWhenDelete(@Param("rgt") int rgt, @Param("offset") int offset);
+  
+  
+  @Override
+  public default Permission insert(Permission entity) {
+
+    if (entity.getParentId() == null) {
+      entity.setParentId("0");
+    }
+
+    if (entity.getParentId() == null || entity.getParentId().isEmpty() || "0".equals(entity.getParentId())) {
+      int maxRgt = selectMaxRgt();
+      entity.setLft((maxRgt+1));
+      entity.setRgt((maxRgt+1) + 1);
+      
+      entity.setLevel(1);
+    } else {
+      Permission parentEntity = this.selectById(entity.getParentId());
+      if (parentEntity == null) {
+        throw new RuntimeException(String.format("父级对象不存在!"));
+      } else {
+        // 将 lft或rgt 大于等于父级对象 rgt 的记录的 lft、rgt +offset
+        int rgt = parentEntity.getRgt();
+        int offset = 2;
+        updateLftRgtWhenInsert(rgt, offset);
+        
+        entity.setLft(rgt);
+        entity.setRgt(rgt + 1);
+        
+        entity.setLevel(parentEntity.getLevel() + 1);
+      }
+    }
+    
+    return BaseJpaRepository.super.insert(entity);
+  }
+  
+  @Override
+  public default Permission update(Permission entity) {
+
+    Permission originEntity = this.selectById(entity.getId());
+    if (originEntity == null) {
+      return null;
+    }
+    
+    //if (!this.checkFieldExists("code", entity.getCode(), entity.getId())) {
+    //  throw new RuntimeException(String.format("代码重复!"));
+    //}
+    
+    if (originEntity.getParentId() == null) {
+      originEntity.setParentId("0");
+    }
+    
+    if (entity.getParentId() == null) {
+      entity.setParentId("0");
+    }
+    
+    if (!originEntity.getParentId().equals(entity.getParentId()) ) {
+
+      int lft = originEntity.getLft();
+      int rgt = originEntity.getRgt();
+      int level = originEntity.getLevel();
+      int offset = rgt - lft +1;
+      
+      List<Permission> childEntities = this.selectBetweenLftRgt(lft, rgt);
+
+      if (entity.getParentId() == null || entity.getParentId().isEmpty() || "0".equals(entity.getParentId())) {
+        // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+        updateLftRgtWhenDelete(rgt, offset);
+  
+        int maxRgt = selectMaxRgt();
+        entity.setLft((maxRgt+1));
+        entity.setRgt((maxRgt+1) + 1 +offset-2);
+        
+        entity.setLevel(1);
+      } else {
+        // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+        updateLftRgtWhenDelete(rgt, offset);
+
+        Permission parentEntity = this.selectById(entity.getParentId());
+        if (parentEntity == null) {
+          throw new RuntimeException(String.format("父级对象不存在!"));
+        }
+        //System.out.println(String.format("pLft %s, pRgt %s", parentEntity.getLft(), parentEntity.getRgt()));
+        if (parentEntity.getLft() >= originEntity.getLft() && parentEntity.getRgt() <= originEntity.getRgt()) {
+          throw new RuntimeException(String.format("不能设置自身或自身的子节点作为父级!"));
+        }
+        
+        //parentEntity = this.selectById(entity.getParentId()); System.out.println(String.format("pLft %s, pRgt %s", parentEntity.getLft(), parentEntity.getRgt()));
+        // 将 lft或rgt 大于等于父级对象 rgt 的记录的 lft、rgt +offset
+        //int pLft = parentEntity.getLft();
+        int pRgt = parentEntity.getRgt();
+        updateLftRgtWhenInsert(pRgt, offset);
+        
+        entity.setLft(pRgt);
+        entity.setRgt(pRgt + 1 + offset-2);
+        
+        entity.setLevel(parentEntity.getLevel() + 1);
+      }
+      
+      int newLft = entity.getLft();
+      int newRgt = entity.getRgt();
+      int newLevel = entity.getLevel();
+      //System.out.println(String.format("newLft %s, newRgt %s, newLevel %s", newLft, newRgt, newLevel));
+      //System.out.println(String.format("lft %s, rgt %s, level %s", lft, rgt, level));
+      for (Permission childEntity : childEntities) {
+        //Permission pEntity = this.selectById(childEntity.getParentId());
+        
+        int cLft = childEntity.getLft();
+        int cRgt = childEntity.getRgt();
+        int cLevel = childEntity.getLevel();
+        
+        childEntity.setLft(cLft + (newLft - lft));
+        childEntity.setRgt(cRgt + (newRgt - rgt));
+        
+        childEntity.setLevel(cLevel + (newLevel - level));
+        
+        BaseJpaRepository.super.update(childEntity);
+      }
+
+    }
+    
+    return BaseJpaRepository.super.update(entity);
+  }
+
+  @Override
+  public default void delete(String id) {
+    
+    Permission originEntity = this.selectById(id);
+    if (originEntity == null) {
+      return;
+    }
+
+    int lft = originEntity.getLft();
+    int rgt = originEntity.getRgt();
+    int offset = rgt - lft +1;
+
+    // FIXME: 判断是否有子节点
+    //if (lft + 1 != rgt) {
+    //  return;
+    //}
+
+    List<Permission> childEntities = this.selectBetweenLftRgt(lft, rgt);
+    for (Permission childEntity : childEntities) {
+      BaseJpaRepository.super.delete(childEntity.getId());
+    }
+    
+    // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+    updateLftRgtWhenDelete(rgt, offset);
+    
+    BaseJpaRepository.super.delete(id);
+  }
+
+  public default Permission selectApplicationPermissionByCode(String code) {
+    Permission probe = new Permission();
+    probe.setCode(code);
+    probe.setType("1");
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("type", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Permission> example = Example.of(probe, matcher);
+    
+    Optional<Permission> o = this.findOne(example);
+    
+    if (o.isPresent()) {
+      return o.get();
+    }
+    
+    return null;
+  }
+  
+ 
+
+  @Query(value = "select p from Permission p "
+      + "inner join RolePermission rp on p.id=rp.permissionId "
+      + "inner join Role r on rp.roleId=r.id "
+      + "inner join AccountRole ar on r.id=ar.roleId "
+      + "inner join Account a on ar.accountId=a.id "
+      + "where a.username=:username "
+      + "and p.lft >= :lft and p.rgt <= :rgt "
+      + "and (:type is null or p.type=:type) "
+      + "and p.status='1' and r.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Permission> selectAccountRolePermissionByUsername(@Param("username") String username, @Param("lft") int lft, @Param("rgt") int rgt, @Param("type") String type);
+  
+  @Query(value = "select p from Permission p "
+      + "inner join RolePermission rp on p.id=rp.permissionId "
+      + "inner join Role r on rp.roleId=r.id "
+      + "inner join GroupRole gr on r.id=gr.roleId "
+      + "inner join Group_ g on gr.groupId=g.id "
+      + "inner join AccountGroup ag on g.id=ag.groupId "
+      + "inner join Account a on ag.accountId=a.id "
+      + "where a.username=:username "
+      + "and p.lft >= :lft and p.rgt <= :rgt "
+      + "and (:type is null or p.type=:type) "
+      + "and p.status='1' and r.status='1' and g.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Permission> selectAccountGroupRolePermissionByUsername(@Param("username") String username, @Param("lft") int lft, @Param("rgt") int rgt, @Param("type") String type);
+
+  public default List<Permission> selectByUsername(String username, String applicationCode, String type) {
+    List<Permission> permissions = new ArrayList<Permission>();
+    
+    Permission applicationPermission = selectApplicationPermissionByCode(applicationCode);
+    if (applicationPermission == null) {
+      return permissions;
+    }
+    
+    int lft = applicationPermission.getLft();
+    int rgt = applicationPermission.getRgt();
+    
+    List<Permission> accountRolePermissions = selectAccountRolePermissionByUsername(username, lft, rgt, type);
+    permissions.addAll(accountRolePermissions);
+    
+    List<Permission> accountGroupRolePermissions = selectAccountGroupRolePermissionByUsername(username, lft, rgt, type);
+    permissions.addAll(accountGroupRolePermissions);
+    
+    return permissions;
+  }
+
+
+
+
+  public default List<Permission> selectList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    
+    Specification<Permission> spec = convertToSpec(mapBean);
+    
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Sort sort = convertToSort(orderBy);
+
+    if (sort == null) {
+      return this.findAll(spec);
+    } else {
+      return this.findAll(spec, sort);
+    }
+  }
+
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ResourceRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ResourceRepository.java
new file mode 100644
index 0000000..ae9055d
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/ResourceRepository.java
@@ -0,0 +1,68 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.Map;
+import java.util.Optional;
+
+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.base.domain.entity.Resource;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface ResourceRepository extends BaseJpaRepository<Resource> {
+
+  @Override
+  public default Page<Resource> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Resource probe = new Resource();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Resource> example = Example.of(probe, matcher);
+    
+    Page<Resource> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+
+  public default Resource selectByCode(String code) {
+    Resource probe = new Resource();
+    probe.setCode(code);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Resource> example = Example.of(probe, matcher);
+    
+    Optional<Resource> o = this.findOne(example);
+    
+    if (o.isPresent()) {
+      return o.get();
+    }
+    
+    return null;
+  }
+  
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RolePermissionRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RolePermissionRepository.java
new file mode 100644
index 0000000..95f2814
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RolePermissionRepository.java
@@ -0,0 +1,193 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+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.base.domain.entity.Permission;
+import com.supwisdom.institute.backend.base.domain.entity.Role;
+import com.supwisdom.institute.backend.base.domain.entity.RolePermission;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface RolePermissionRepository extends BaseJpaRepository<RolePermission> {
+
+  public default Page<RolePermission> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    Page<RolePermission> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<RolePermission> selectRolePermissions(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<RolePermission> page = this.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateRolePermissions(Role role, List<RolePermission> rolePermissions) {
+
+    List<RolePermission> existRolePermissions = this.selectListByRoleId(role.getId());
+
+    Map<String, RolePermission> existMapRolePermissions = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existRolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+      existMapRolePermissions.put(k, rolePermission);
+    }
+
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+
+      if (existMapRolePermissions.containsKey(k)) {
+        existMapRolePermissions.remove(k);
+      } else {
+        rolePermission.setCompanyId(role.getCompanyId());
+        rolePermission.setRoleId(role.getId());
+
+        this.insert(rolePermission);
+      }
+    }
+
+    for (RolePermission rolePermission : existMapRolePermissions.values()) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+  public default List<RolePermission> selectListByRoleId(String roleId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("roleId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = this.findAll(example);
+
+    return rolePermissions;
+  }
+
+  public default void relatePermissionRoles(Permission permission, List<RolePermission> rolePermissions) {
+
+    // 获取权限已关联的角色
+    List<RolePermission> existPermissionRoles = this.selectListByPermissionId(permission.getId());
+
+    Map<String, RolePermission> existMapPermissionRoles = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existPermissionRoles) {
+      String k = String.format("%s", rolePermission.getRoleId());
+      existMapPermissionRoles.put(k, rolePermission);
+    }
+
+    // 保存未关联的角色
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getRoleId());
+
+      if (existMapPermissionRoles.containsKey(k)) {
+        existMapPermissionRoles.remove(k);
+      } else {
+        rolePermission.setCompanyId(permission.getCompanyId());
+        rolePermission.setPermissionId(permission.getId());
+
+        this.insert(rolePermission);
+      }
+    }
+
+    // 删除移除关联的角色
+    for (RolePermission rolePermission : existMapPermissionRoles.values()) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+  public default List<RolePermission> selectListByPermissionId(String permissionId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setPermissionId(permissionId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("permissionId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = this.findAll(example);
+
+    return rolePermissions;
+  }
+
+  public default RolePermission selectOneByRolePermission(String roleId, String permissionId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+    probe.setPermissionId(permissionId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact())
+        ;
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+    
+    Optional<RolePermission> o = this.findOne(example);
+    
+    return o.isPresent() ? o.get() : null;
+  }
+
+  public default void addRolePermission(String roleId, String permissionId) {
+
+    RolePermission rolePermission = this.selectOneByRolePermission(roleId, permissionId);
+    
+    if (rolePermission == null) {
+      rolePermission = new RolePermission();
+      //rolePermission.setCompanyId(companyId);
+      rolePermission.setRoleId(roleId);
+      rolePermission.setPermissionId(permissionId);
+      
+      this.insert(rolePermission);
+    }
+  }
+
+  public default void removeRolePermission(String roleId, String permissionId) {
+
+    RolePermission rolePermission = this.selectOneByRolePermission(roleId, permissionId);
+    
+    if (rolePermission != null) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RoleRepository.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RoleRepository.java
new file mode 100644
index 0000000..b416a7e
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/repo/RoleRepository.java
@@ -0,0 +1,101 @@
+package com.supwisdom.institute.backend.base.domain.repo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+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.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.base.domain.entity.Role;
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Repository
+public interface RoleRepository extends BaseJpaRepository<Role> {
+
+  @Override
+  public default Page<Role> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Role probe = new Role();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Role> example = Example.of(probe, matcher);
+    
+    Page<Role> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+  
+  
+  public default Role selectByCode(String code) {
+    Role probe = new Role();
+    probe.setCode(code);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Role> example = Example.of(probe, matcher);
+    
+    Optional<Role> o = this.findOne(example);
+    
+    if (o.isPresent()) {
+      return o.get();
+    }
+    
+    return null;
+  }
+  
+  @Query(value = "select r from Role r "
+      + "inner join AccountRole ar on r.id=ar.roleId "
+      + "inner join Account a on ar.accountId=a.id "
+      + "where a.username=:username "
+      + "and r.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Role> selectAccountRoleByUsername(@Param("username") String username);
+  
+  @Query(value = "select r from Role r "
+      + "inner join GroupRole gr on r.id=gr.roleId "
+      + "inner join Group_ g on gr.groupId=g.id "
+      + "inner join AccountGroup ag on g.id=ag.groupId "
+      + "inner join Account a on ag.accountId=a.id "
+      + "where a.username=:username "
+      + "and r.status='1' and g.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Role> selectAccountGroupRoleByUsername(@Param("username") String username);
+
+  public default List<Role> selectByUsername(String username) {
+    List<Role> roles = new ArrayList<Role>();
+    
+    List<Role> userRoles = selectAccountRoleByUsername(username);
+    roles.addAll(userRoles);
+    
+    List<Role> userGroupRoles = selectAccountGroupRoleByUsername(username);
+    roles.addAll(userGroupRoles);
+    
+    return roles;
+  }
+  
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/.gitkeep b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/.gitkeep
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/AccountService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/AccountService.java
new file mode 100644
index 0000000..ece1cda
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/AccountService.java
@@ -0,0 +1,199 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.Account;
+import com.supwisdom.institute.backend.base.domain.entity.AccountGroup;
+import com.supwisdom.institute.backend.base.domain.entity.AccountRole;
+import com.supwisdom.institute.backend.base.domain.repo.AccountGroupRepository;
+import com.supwisdom.institute.backend.base.domain.repo.AccountRepository;
+import com.supwisdom.institute.backend.base.domain.repo.AccountRoleRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Service
+public class AccountService extends ABaseService<Account, AccountRepository> {
+  
+  @Override
+  public AccountRepository getRepo() {
+    return accountRepository;
+  }
+
+  @Autowired
+  private AccountRepository accountRepository;
+
+  @Autowired
+  private AccountGroupRepository accountGroupRepository;
+
+  @Autowired
+  private AccountRoleRepository accountRoleRepository;
+  
+  
+  @Override
+  public Account insert(Account entity) {
+
+    entity.setEnabled(Account.STATUS_ENABLED.equals(entity.getStatus()));
+    entity.setAccountNonExpired(true);
+    entity.setAccountNonLocked(true);
+    entity.setCredentialsNonExpired(true);
+    
+    return super.insert(entity);
+  }
+  
+  @Override
+  public Account update(Account entity) {
+    
+    entity.setEnabled(Account.STATUS_ENABLED.equals(entity.getStatus()));
+
+    return super.update(entity);
+  }
+  
+
+  public void deleteBatch(List<String> ids) {
+    
+    ids.stream().forEach(id -> {
+      this.deleteById(id);
+    });
+  }
+
+
+  public Page<AccountGroup> selectAccountGroups(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountGroup probe = new AccountGroup();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountGroup> page = accountGroupRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateAccountGroups(Account account, List<AccountGroup> accountGroups) {
+
+    List<AccountGroup> existAccountGroups = this.selectAccountGroupsByAccountId(account.getId());
+
+    Map<String, AccountGroup> existMapAccountGroups = new LinkedHashMap<String, AccountGroup>();
+    for (AccountGroup accountGroup : existAccountGroups) {
+      String k = String.format("%s", accountGroup.getGroupId());
+      existMapAccountGroups.put(k, accountGroup);
+    }
+
+    for (AccountGroup accountGroup : accountGroups) {
+      String k = String.format("%s", accountGroup.getGroupId());
+
+      if (existMapAccountGroups.containsKey(k)) {
+        existMapAccountGroups.remove(k);
+      } else {
+        accountGroup.setCompanyId(account.getCompanyId());
+        accountGroup.setAccountId(account.getId());
+
+        accountGroupRepository.insert(accountGroup);
+      }
+    }
+
+    for (AccountGroup accountGroup : existMapAccountGroups.values()) {
+      accountGroupRepository.deleteById(accountGroup.getId());
+    }
+  }
+
+  public List<AccountGroup> selectAccountGroupsByAccountId(String accountId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setAccountId(accountId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    List<AccountGroup> accountGroups = accountGroupRepository.findAll(example);
+
+    return accountGroups;
+  }
+
+  
+
+  public Page<AccountRole> selectAccountRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountRole probe = new AccountRole();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountRole> page = accountRoleRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateAccountRoles(Account account, List<AccountRole> accountRoles) {
+
+    List<AccountRole> existAccountRoles = this.selectAccountRolesByAccountId(account.getId());
+
+    Map<String, AccountRole> existMapAccountRoles = new LinkedHashMap<String, AccountRole>();
+    for (AccountRole accountRole : existAccountRoles) {
+      String k = String.format("%s", accountRole.getRoleId());
+      existMapAccountRoles.put(k, accountRole);
+    }
+
+    for (AccountRole accountRole : accountRoles) {
+      String k = String.format("%s", accountRole.getRoleId());
+
+      if (existMapAccountRoles.containsKey(k)) {
+        existMapAccountRoles.remove(k);
+      } else {
+        accountRole.setCompanyId(account.getCompanyId());
+        accountRole.setAccountId(account.getId());
+
+        accountRoleRepository.insert(accountRole);
+      }
+    }
+
+    for (AccountRole accountRole : existMapAccountRoles.values()) {
+      accountRoleRepository.deleteById(accountRole.getId());
+    }
+  }
+
+  public List<AccountRole> selectAccountRolesByAccountId(String accountId) {
+
+    AccountRole probe = new AccountRole();
+    probe.setAccountId(accountId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    List<AccountRole> accountRoles = accountRoleRepository.findAll(example);
+
+    return accountRoles;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ConfigService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ConfigService.java
new file mode 100644
index 0000000..d41e362
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ConfigService.java
@@ -0,0 +1,26 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.Config;
+import com.supwisdom.institute.backend.base.domain.repo.ConfigRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+
+@Service
+public class ConfigService extends ABaseService<Config, ConfigRepository> {
+  
+  @Override
+  public ConfigRepository getRepo() {
+    return configRepository;
+  }
+
+  @Autowired
+  private ConfigRepository configRepository;
+
+  public Config selectByCategoryKey(String categoryCode, String configKey) {
+    
+    return configRepository.selectByCategoryKey(categoryCode, configKey);
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/GroupService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/GroupService.java
new file mode 100644
index 0000000..f8b4f11
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/GroupService.java
@@ -0,0 +1,175 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.AccountGroup;
+import com.supwisdom.institute.backend.base.domain.entity.Group;
+import com.supwisdom.institute.backend.base.domain.entity.GroupRole;
+import com.supwisdom.institute.backend.base.domain.repo.AccountGroupRepository;
+import com.supwisdom.institute.backend.base.domain.repo.GroupRepository;
+import com.supwisdom.institute.backend.base.domain.repo.GroupRoleRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Service
+public class GroupService extends ABaseService<Group, GroupRepository> {
+  
+  @Override
+  public GroupRepository getRepo() {
+    return groupRepository;
+  }
+
+  @Autowired
+  private GroupRepository groupRepository;
+
+  @Autowired
+  private AccountGroupRepository accountGroupRepository;
+
+  @Autowired
+  private GroupRoleRepository groupRoleRepository;
+
+
+
+  public Page<AccountGroup> selectGroupAccounts(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountGroup probe = new AccountGroup();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountGroup> page = accountGroupRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateGroupAccounts(Group group, List<AccountGroup> accountGroups) {
+
+    List<AccountGroup> existGroupAccounts = this.selectGroupAccountsByGroupId(group.getId());
+
+    Map<String, AccountGroup> existMapGroupAccounts = new LinkedHashMap<String, AccountGroup>();
+    for (AccountGroup accountGroup : existGroupAccounts) {
+      String k = String.format("%s", accountGroup.getAccountId());
+      existMapGroupAccounts.put(k, accountGroup);
+    }
+
+    for (AccountGroup accountGroup : accountGroups) {
+      String k = String.format("%s", accountGroup.getAccountId());
+
+      if (existMapGroupAccounts.containsKey(k)) {
+        existMapGroupAccounts.remove(k);
+      } else {
+        accountGroup.setCompanyId(group.getCompanyId());
+        accountGroup.setGroupId(group.getId());
+
+        accountGroupRepository.insert(accountGroup);
+      }
+    }
+
+    for (AccountGroup accountGroup : existMapGroupAccounts.values()) {
+      accountGroupRepository.deleteById(accountGroup.getId());
+    }
+  }
+
+  public List<AccountGroup> selectGroupAccountsByGroupId(String groupId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    List<AccountGroup> accountGroups = accountGroupRepository.findAll(example);
+
+    return accountGroups;
+  }
+  
+  
+  
+
+  public Page<GroupRole> selectGroupRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupRole> page = groupRoleRepository.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateGroupRoles(Group group, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existGroupRoles = this.selectGroupRolesByGroupId(group.getId());
+
+    Map<String, GroupRole> existMapGroupRoles = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existGroupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+      existMapGroupRoles.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+
+      if (existMapGroupRoles.containsKey(k)) {
+        existMapGroupRoles.remove(k);
+      } else {
+        groupRole.setCompanyId(group.getCompanyId());
+        groupRole.setGroupId(group.getId());
+
+        groupRoleRepository.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapGroupRoles.values()) {
+      groupRoleRepository.deleteById(groupRole.getId());
+    }
+  }
+
+  public List<GroupRole> selectGroupRolesByGroupId(String groupId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("groupId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = groupRoleRepository.findAll(example);
+
+    return groupRoles;
+  }
+
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/PermissionService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/PermissionService.java
new file mode 100644
index 0000000..f2cfe4b
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/PermissionService.java
@@ -0,0 +1,71 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.Permission;
+import com.supwisdom.institute.backend.base.domain.model.PermissionTreeNode;
+import com.supwisdom.institute.backend.base.domain.repo.PermissionRepository;
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+
+@Slf4j
+@Service
+public class PermissionService extends ABaseService<Permission, PermissionRepository> {
+  
+  @Override
+  public PermissionRepository getRepo() {
+    return permissionRepository;
+  }
+
+  @Autowired
+  private PermissionRepository permissionRepository;
+
+  public void deleteBatch(List<String> ids) {
+    
+    ids.stream().forEach(id -> {
+      this.deleteById(id);
+    });
+  }
+
+  public PermissionTreeNode selectPermissionTree(Map<String, Object> mapBean) {
+    
+    List<Permission> permissions = permissionRepository.selectList(true, -1, -1, mapBean, null);
+    
+    Map<String, PermissionTreeNode> parentTreeNode = new LinkedHashMap<String, PermissionTreeNode>();
+    
+    PermissionTreeNode rootTreeNode = new PermissionTreeNode();
+    rootTreeNode.setId(Permission.ROOT_PARENT_ID);
+    rootTreeNode.setCode("ROOT");
+    rootTreeNode.setName("顶级菜单");
+    rootTreeNode.setChildren(new ArrayList<PermissionTreeNode>());
+    
+    parentTreeNode.put(rootTreeNode.getId(), rootTreeNode);
+    
+    for (Permission permission : permissions) {
+      PermissionTreeNode treeNode = EntityUtils.copy(permission, new PermissionTreeNode());
+      treeNode.setChildren(new ArrayList<PermissionTreeNode>());
+      
+      parentTreeNode.put(treeNode.getId(), treeNode);
+    }
+    
+    for (PermissionTreeNode treeNode : parentTreeNode.values()) {
+      if (!parentTreeNode.containsKey(treeNode.getParentId())) {
+        continue;
+      }
+      
+      parentTreeNode.get(treeNode.getParentId()).getChildren().add(treeNode);
+    }
+    
+    return rootTreeNode;
+  }
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ResourceService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ResourceService.java
new file mode 100644
index 0000000..075fa74
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/ResourceService.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.Resource;
+import com.supwisdom.institute.backend.base.domain.repo.ResourceRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+
+@Service
+public class ResourceService extends ABaseService<Resource, ResourceRepository> {
+  
+  @Override
+  public ResourceRepository getRepo() {
+    return resourceRepository;
+  }
+
+  @Autowired
+  private ResourceRepository resourceRepository;
+
+}
diff --git a/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/RoleService.java b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/RoleService.java
new file mode 100644
index 0000000..1239d2f
--- /dev/null
+++ b/base/domain/src/main/java/com/supwisdom/institute/backend/base/domain/service/RoleService.java
@@ -0,0 +1,249 @@
+package com.supwisdom.institute.backend.base.domain.service;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.Service;
+
+import com.supwisdom.institute.backend.base.domain.entity.AccountRole;
+import com.supwisdom.institute.backend.base.domain.entity.GroupRole;
+import com.supwisdom.institute.backend.base.domain.entity.Role;
+import com.supwisdom.institute.backend.base.domain.entity.RolePermission;
+import com.supwisdom.institute.backend.base.domain.repo.AccountRoleRepository;
+import com.supwisdom.institute.backend.base.domain.repo.GroupRoleRepository;
+import com.supwisdom.institute.backend.base.domain.repo.RolePermissionRepository;
+import com.supwisdom.institute.backend.base.domain.repo.RoleRepository;
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+
+@Service
+public class RoleService extends ABaseService<Role, RoleRepository> {
+  
+  @Override
+  public RoleRepository getRepo() {
+    return roleRepository;
+  }
+
+  @Autowired
+  private RoleRepository roleRepository;
+
+  @Autowired
+  private AccountRoleRepository accountRoleRepository;
+
+  @Autowired
+  private GroupRoleRepository groupRoleRepository;
+
+  @Autowired
+  private RolePermissionRepository rolePermissionRepository;
+
+  
+
+  public void deleteBatch(List<String> ids) {
+    
+    ids.stream().forEach(id -> {
+      this.deleteById(id);
+    });
+  }
+
+  public Page<AccountRole> selectRoleAccounts(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountRole probe = new AccountRole();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountRole> page = accountRoleRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateRoleAccounts(Role role, List<AccountRole> roleAccounts) {
+
+    List<AccountRole> existRoleAccounts = this.selectRoleAccountsByRoleId(role.getId());
+
+    Map<String, AccountRole> existMapRoleAccounts = new LinkedHashMap<String, AccountRole>();
+    for (AccountRole accountRole : existRoleAccounts) {
+      String k = String.format("%s", accountRole.getAccountId());
+      existMapRoleAccounts.put(k, accountRole);
+    }
+
+    for (AccountRole accountRole : roleAccounts) {
+      String k = String.format("%s", accountRole.getAccountId());
+
+      if (existMapRoleAccounts.containsKey(k)) {
+        existMapRoleAccounts.remove(k);
+      } else {
+        accountRole.setCompanyId(role.getCompanyId());
+        accountRole.setRoleId(role.getId());
+
+        accountRoleRepository.insert(accountRole);
+      }
+    }
+
+    for (AccountRole accountRole : existMapRoleAccounts.values()) {
+      accountRoleRepository.deleteById(accountRole.getId());
+    }
+  }
+
+  public List<AccountRole> selectRoleAccountsByRoleId(String roleId) {
+
+    AccountRole probe = new AccountRole();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountRole> example = Example.of(probe, matcher);
+
+    List<AccountRole> accountRoles = accountRoleRepository.findAll(example);
+
+    return accountRoles;
+  }
+  
+  
+
+  public Page<GroupRole> selectRoleGroups(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupRole> page = groupRoleRepository.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateRoleGroups(Role role, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existRoleGroups = this.selectRoleGroupsByRoleId(role.getCode());
+
+    Map<String, GroupRole> existMapRoleGroups = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existRoleGroups) {
+      String k = String.format("%s", groupRole.getGroupId());
+      existMapRoleGroups.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getGroupId());
+
+      if (existMapRoleGroups.containsKey(k)) {
+        existMapRoleGroups.remove(k);
+      } else {
+        groupRole.setCompanyId(role.getCompanyId());
+        groupRole.setRoleId(role.getId());
+
+        groupRoleRepository.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapRoleGroups.values()) {
+      groupRoleRepository.deleteById(groupRole.getId());
+    }
+  }
+
+  public List<GroupRole> selectRoleGroupsByRoleId(String roleId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = groupRoleRepository.findAll(example);
+
+    return groupRoles;
+  }
+
+
+  public Page<RolePermission> selectRolePermissions(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<RolePermission> page = rolePermissionRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateRolePermissions(Role role, List<RolePermission> rolePermissions) {
+
+    List<RolePermission> existRolePermissions = this.selectRolePermissionsByRoleId(role.getId());
+
+    Map<String, RolePermission> existMapRolePermissions = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existRolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+      existMapRolePermissions.put(k, rolePermission);
+    }
+
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+
+      if (existMapRolePermissions.containsKey(k)) {
+        existMapRolePermissions.remove(k);
+      } else {
+        rolePermission.setCompanyId(role.getCompanyId());
+        rolePermission.setRoleId(role.getId());
+
+        rolePermissionRepository.insert(rolePermission);
+      }
+    }
+
+    for (RolePermission rolePermission : existMapRolePermissions.values()) {
+      rolePermissionRepository.deleteById(rolePermission.getId());
+    }
+  }
+
+  public List<RolePermission> selectRolePermissionsByRoleId(String roleId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("roleId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = rolePermissionRepository.findAll(example);
+
+    return rolePermissions;
+  }
+
+}