diff --git a/doc/sql/easy_retry_mysql.sql b/doc/sql/easy_retry_mysql.sql
index b7e70ffb..c5aa7fc1 100644
--- a/doc/sql/easy_retry_mysql.sql
+++ b/doc/sql/easy_retry_mysql.sql
@@ -468,6 +468,7 @@ CREATE TABLE `workflow_node`
     `namespace_id`         varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
     `group_name`           varchar(64)         NOT NULL COMMENT '组名称',
     `job_id`               bigint(20)          NOT NULL COMMENT '任务信息id',
+    `workflow_id`               bigint(20)          NOT NULL COMMENT '工作流ID',
     `node_type`            tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点',
     `expression_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL',
     `fail_strategy`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '失败策略 1、跳过 2、阻塞',
diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java
index e60bc379..3411f5c3 100644
--- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java
+++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java
@@ -8,6 +8,9 @@ import java.time.LocalDateTime;
 import lombok.Getter;
 import lombok.Setter;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
 /**
  * <p>
  * 工作流
@@ -40,10 +43,25 @@ public class Workflow implements Serializable {
      */
     private String groupName;
 
+    /**
+     * 触发类型
+     */
+    private Integer triggerType;
+
+    /**
+     * 触发间隔
+     */
+    private String triggerInterval;
+
+    /**
+     * 执行超时时间
+     */
+    private Integer executorTimeout;
+
     /**
      * 工作流状态 0、关闭、1、开启
      */
-    private Byte workflowStatus;
+    private Integer workflowStatus;
 
     /**
      * 任务执行时间
diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java
index 581281de..235d8163 100644
--- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java
+++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java
@@ -44,6 +44,11 @@ public class WorkflowNode implements Serializable {
      */
     private Long jobId;
 
+    /**
+     * 工作流ID
+     */
+    private Long workflowId;
+
     /**
      * 1、任务节点 2、条件节点
      */
diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java
index 68325704..a35272c3 100644
--- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java
+++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java
@@ -4,6 +4,7 @@ import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO;
 import com.aizuda.easy.retry.server.web.service.WorkflowService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -18,9 +19,8 @@ public class WorkflowController {
 
     private final WorkflowService workflowService;
 
-    @Autowired
     @PostMapping
-    public Boolean saveWorkflow(@RequestBody WorkflowRequestVO workflowRequestVO) {
+    public Boolean saveWorkflow(@RequestBody @Validated WorkflowRequestVO workflowRequestVO) {
         return workflowService.saveWorkflow(workflowRequestVO);
     }
 
diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java
index 582793bd..f769c8d8 100644
--- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java
+++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java
@@ -21,7 +21,7 @@ public class WorkflowRequestVO {
     @Pattern(regexp = "^[A-Za-z0-9_]{1,64}$", message = "仅支持长度为1~64字符且类型为数字、字母和下划线")
     private String groupName;
 
-    @NotBlank(message = "触发类型不能为空")
+    @NotNull(message = "触发类型不能为空")
     private Integer triggerType;
 
     @NotBlank(message = "触发间隔不能为空")
@@ -30,34 +30,62 @@ public class WorkflowRequestVO {
     @NotNull(message = "执行超时时间不能为空")
     private Integer executorTimeout;
 
-    @NotEmpty(message = "执行超时时间不能为空")
-    @Valid
+    /**
+     * 0、关闭、1、开启
+     */
+    @NotNull(message = "工作流状态")
+    private Integer workflowStatus;
+
+    @NotEmpty(message = "节点信息不能为空")
     private List<NodeInfo> nodeInfos;
 
     @Data
     public static class NodeInfo {
 
+        /**
+         * 优先级
+         */
+        private Integer priorityLevel;
+
+        /**
+         * 1、任务节点 2、条件节点
+         */
+        @NotNull(message = "节点类型不能为空 ")
+        private Integer nodeType;
+
+        /**
+         * 任务ID
+         */
+        @NotNull(message = "任务ID不能为空")
+        private Long jobId;
+
+        /**
+         * 表达式类型 1、SpEl、2、Aviator 3、QL
+         */
+        @NotNull(message = "表达式类型不能为空")
+        private Integer expressionType;
+
         /**
          * 条件节点表达式
          */
         private String nodeExpression;
 
-        @NotNull(message = "节点类型不能为空")
-        private Integer nodeType;
-
-        @NotNull(message = "任务ID不能为空")
-        private Long jobId;
-
-        @NotNull(message = "表达式类型不能为空")
-        private Integer expressionType;
-
+        /**
+         * 1、跳过 2、阻塞
+         */
         @NotNull(message = "失败策略不能为空")
         private Integer failStrategy;
 
+        /**
+         * 工作流状态  0、关闭、1、开启
+         */
+        @NotNull(message = "工作流状态不能为空")
+        private Integer workflowNodeStatus;
+
         /**
          * 子节点
          */
-        private List<NodeInfo> childrenList;
+        private List<NodeInfo> childreList;
 
     }
 
diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java
new file mode 100644
index 00000000..2fe6e2df
--- /dev/null
+++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java
@@ -0,0 +1,25 @@
+package com.aizuda.easy.retry.server.web.service.convert;
+
+import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO;
+import com.aizuda.easy.retry.template.datasource.persistence.po.Workflow;
+import com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowNode;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * @author: xiaowoniu
+ * @date : 2023-12-13
+ * @since : 2.5.0
+ */
+@Mapper
+public interface WorkflowConverter {
+
+    WorkflowConverter INSTANCE = Mappers.getMapper(WorkflowConverter.class);
+
+    Workflow toWorkflow(WorkflowRequestVO workflowRequestVO);
+
+    WorkflowNode toWorkflowNode(WorkflowRequestVO.NodeInfo nodeInfo);
+
+}
diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java
index 010d4399..e607205a 100644
--- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java
+++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java
@@ -1,8 +1,28 @@
 package com.aizuda.easy.retry.server.web.service.impl;
 
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
+import com.aizuda.easy.retry.common.core.util.JsonUtil;
+import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
 import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO;
+import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO.NodeInfo;
 import com.aizuda.easy.retry.server.web.service.WorkflowService;
+import com.aizuda.easy.retry.server.web.service.convert.WorkflowConverter;
+import com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowMapper;
+import com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowNodeMapper;
+import com.aizuda.easy.retry.template.datasource.persistence.po.Workflow;
+import com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowNode;
+import com.google.common.collect.Lists;
+import com.google.common.graph.GraphBuilder;
+import com.google.common.graph.MutableGraph;
+import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @author xiaowoniu
@@ -10,10 +30,65 @@ import org.springframework.stereotype.Service;
  * @since 2.6.0
  */
 @Service
+@RequiredArgsConstructor
 public class WorkflowServiceImpl implements WorkflowService {
-
+    private final WorkflowMapper workflowMapper;
+    private final WorkflowNodeMapper workflowNodeMapper;
     @Override
+    @Transactional
     public boolean saveWorkflow(WorkflowRequestVO workflowRequestVO) {
-        return false;
+
+        Long root = -1L;
+        MutableGraph<Long> graph = GraphBuilder.directed().build();
+        // 添加虚拟头节点
+        graph.addNode(root);
+
+        // 组装工作流信息
+        Workflow workflow = WorkflowConverter.INSTANCE.toWorkflow(workflowRequestVO);
+        workflow.setFlowInfo(StrUtil.EMPTY);
+        Assert.isTrue(1 ==  workflowMapper.insert(workflow), () -> new EasyRetryServerException("新增工作流失败"));
+
+        // 组装节点信息
+        List<NodeInfo> nodeInfos = workflowRequestVO.getNodeInfos();
+
+        // 递归构建图
+        buildGraph(root, workflowRequestVO.getGroupName(), workflow.getId(), nodeInfos, graph);
+
+        // 保存图信息
+        workflow.setFlowInfo(JsonUtil.toJsonString(convertGraphToAdjacencyList(graph)));
+        workflowMapper.updateById(workflow);
+
+        return true;
     }
+
+    private Map<Long, Iterable<Long>> convertGraphToAdjacencyList(MutableGraph<Long> graph) {
+        Map<Long, Iterable<Long>> adjacencyList = new HashMap<>();
+
+        for (Long node : graph.nodes()) {
+            adjacencyList.put(node, graph.successors(node));
+        }
+
+        return adjacencyList;
+    }
+
+    public void buildGraph(Long parentId, String groupName, Long workflowId, List<NodeInfo> nodeInfos, MutableGraph<Long> graph) {
+
+        if (CollectionUtils.isEmpty(nodeInfos)) {
+            return;
+        }
+
+        for (final NodeInfo nodeInfo : nodeInfos) {
+            WorkflowNode workflowNode = WorkflowConverter.INSTANCE.toWorkflowNode(nodeInfo);
+            workflowNode.setWorkflowId(workflowId);
+            workflowNode.setGroupName(groupName);
+            Assert.isTrue(1 ==  workflowNodeMapper.insert(workflowNode), () -> new EasyRetryServerException("新增工作流节点失败"));
+            // 添加节点
+            graph.addNode(workflowNode.getId());
+            // 添加边
+            graph.putEdge(parentId, workflowNode.getId());
+            buildGraph(workflowNode.getId(), groupName, workflowId, nodeInfo.getChildreList(), graph);
+        }
+    }
+
+
 }