diff --git a/cmd/task/main.go b/cmd/task/main.go
index e31f03b83bafe6af209aa2a8d75d008fe0418428..7e5d905c8a1eea722d50cc626bbf7a989b454b1e 100644
--- a/cmd/task/main.go
+++ b/cmd/task/main.go
@@ -22,8 +22,10 @@ import (
 	goahealthsrv "code.vereign.com/gaiax/tsa/task/gen/http/health/server"
 	goaopenapisrv "code.vereign.com/gaiax/tsa/task/gen/http/openapi/server"
 	goatasksrv "code.vereign.com/gaiax/tsa/task/gen/http/task/server"
+	goatasklistsrv "code.vereign.com/gaiax/tsa/task/gen/http/task_list/server"
 	"code.vereign.com/gaiax/tsa/task/gen/openapi"
 	goatask "code.vereign.com/gaiax/tsa/task/gen/task"
+	goatasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
 	"code.vereign.com/gaiax/tsa/task/internal/clients/cache"
 	"code.vereign.com/gaiax/tsa/task/internal/clients/policy"
 	"code.vereign.com/gaiax/tsa/task/internal/config"
@@ -31,6 +33,7 @@ import (
 	"code.vereign.com/gaiax/tsa/task/internal/service"
 	"code.vereign.com/gaiax/tsa/task/internal/service/health"
 	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist"
 	"code.vereign.com/gaiax/tsa/task/internal/storage"
 )
 
@@ -86,22 +89,26 @@ func main() {
 
 	// create services
 	var (
-		taskSvc   goatask.Service
-		healthSvc goahealth.Service
+		taskSvc     goatask.Service
+		taskListSvc goatasklist.Service
+		healthSvc   goahealth.Service
 	)
 	{
 		taskSvc = task.New(storage, storage, cache, logger)
+		taskListSvc = tasklist.New(storage, storage, logger)
 		healthSvc = health.New()
 	}
 
 	// create endpoints
 	var (
-		taskEndpoints    *goatask.Endpoints
-		healthEndpoints  *goahealth.Endpoints
-		openapiEndpoints *openapi.Endpoints
+		taskEndpoints     *goatask.Endpoints
+		taskListEndpoints *goatasklist.Endpoints
+		healthEndpoints   *goahealth.Endpoints
+		openapiEndpoints  *openapi.Endpoints
 	)
 	{
 		taskEndpoints = goatask.NewEndpoints(taskSvc)
+		taskListEndpoints = goatasklist.NewEndpoints(taskListSvc)
 		healthEndpoints = goahealth.NewEndpoints(healthSvc)
 		openapiEndpoints = openapi.NewEndpoints(nil)
 	}
@@ -124,18 +131,21 @@ func main() {
 	// the service input and output data structures to HTTP requests and
 	// responses.
 	var (
-		taskServer    *goatasksrv.Server
-		healthServer  *goahealthsrv.Server
-		openapiServer *goaopenapisrv.Server
+		taskServer     *goatasksrv.Server
+		taskListServer *goatasklistsrv.Server
+		healthServer   *goahealthsrv.Server
+		openapiServer  *goaopenapisrv.Server
 	)
 	{
 		taskServer = goatasksrv.New(taskEndpoints, mux, dec, enc, nil, errFormatter)
+		taskListServer = goatasklistsrv.New(taskListEndpoints, mux, dec, enc, nil, errFormatter)
 		healthServer = goahealthsrv.New(healthEndpoints, mux, dec, enc, nil, errFormatter)
 		openapiServer = goaopenapisrv.New(openapiEndpoints, mux, dec, enc, nil, errFormatter, nil, nil)
 	}
 
 	// Configure the mux.
 	goatasksrv.Mount(mux, taskServer)
+	goatasklistsrv.Mount(mux, taskListServer)
 	goahealthsrv.Mount(mux, healthServer)
 	goaopenapisrv.Mount(mux, openapiServer)
 
diff --git a/design/design.go b/design/design.go
index f78f0680296dcbe79ae5a2edd5e413d12446c117..19bce998ec88c06dcd99234fa87b4ca34afb399f 100644
--- a/design/design.go
+++ b/design/design.go
@@ -20,8 +20,8 @@ var _ = Service("task", func() {
 
 	Method("Create", func() {
 		Description("Create a task and put it in a queue for execution.")
-		Payload(CreateRequest)
-		Result(CreateResult)
+		Payload(CreateTaskRequest)
+		Result(CreateTaskResult)
 		HTTP(func() {
 			POST("/v1/task/{taskName}")
 
@@ -49,6 +49,30 @@ var _ = Service("task", func() {
 	})
 })
 
+var _ = Service("taskList", func() {
+	Description("TaskList service provides endpoints to work with task lists.")
+
+	Method("Create", func() {
+		Description("Create a task list and corresponding tasks and put them in respective queues for execution.")
+		Payload(CreateTaskListRequest)
+		Result(CreateTaskListResult)
+		HTTP(func() {
+			POST("/v1/taskList/{taskListName}")
+
+			Header("cacheNamespace:x-cache-namespace", String, "Cache key namespace", func() {
+				Example("login")
+			})
+			Header("cacheScope:x-cache-scope", String, "Cache key scope", func() {
+				Example("user")
+			})
+
+			Body("data")
+
+			Response(StatusOK)
+		})
+	})
+})
+
 var _ = Service("health", func() {
 	Description("Health service provides health check endpoints.")
 
diff --git a/design/types.go b/design/types.go
index 7625fe78437e5f08fb4a3a4c2c9cce2f699b316f..7178a145f82034751203139cd631fcca56bdbf0d 100644
--- a/design/types.go
+++ b/design/types.go
@@ -3,7 +3,7 @@ package design
 
 import . "goa.design/goa/v3/dsl"
 
-var CreateRequest = Type("CreateRequest", func() {
+var CreateTaskRequest = Type("CreateTaskRequest", func() {
 	Field(1, "taskName", String, "Task name.")
 	Field(2, "data", Any, "Data contains JSON payload that will be used for task execution.")
 	Field(3, "cacheNamespace", String, "Cache key namespace.")
@@ -11,7 +11,7 @@ var CreateRequest = Type("CreateRequest", func() {
 	Required("taskName", "data")
 })
 
-var CreateResult = Type("CreateResult", func() {
+var CreateTaskResult = Type("CreateTaskResult", func() {
 	Field(1, "taskID", String, "Unique task identifier.")
 	Required("taskID")
 })
@@ -20,3 +20,16 @@ var TaskResultRequest = Type("TaskResultRequest", func() {
 	Field(1, "taskID", String, "Unique task identifier.")
 	Required("taskID")
 })
+
+var CreateTaskListRequest = Type("CreateTaskListRequest", func() {
+	Field(1, "taskListName", String, "TaskList name.")
+	Field(2, "data", Any, "Data contains JSON payload that will be used for taskList execution.")
+	Field(3, "cacheNamespace", String, "Cache key namespace.")
+	Field(4, "cacheScope", String, "Cache key scope.")
+	Required("taskListName", "data")
+})
+
+var CreateTaskListResult = Type("CreateTaskListResult", func() {
+	Field(1, "taskListID", String, "Unique taskList identifier.")
+	Required("taskListID")
+})
diff --git a/gen/http/cli/task/cli.go b/gen/http/cli/task/cli.go
index ca12630d5df90424c74955045a70afd451dcb583..e125d9bae7407f0fabda3324cb9c3d1966b29ed4 100644
--- a/gen/http/cli/task/cli.go
+++ b/gen/http/cli/task/cli.go
@@ -15,6 +15,7 @@ import (
 
 	healthc "code.vereign.com/gaiax/tsa/task/gen/http/health/client"
 	taskc "code.vereign.com/gaiax/tsa/task/gen/http/task/client"
+	tasklistc "code.vereign.com/gaiax/tsa/task/gen/http/task_list/client"
 	goahttp "goa.design/goa/v3/http"
 	goa "goa.design/goa/v3/pkg"
 )
@@ -26,13 +27,15 @@ import (
 func UsageCommands() string {
 	return `health (liveness|readiness)
 task (create|task-result)
+task-list create
 `
 }
 
 // UsageExamples produces an example of a valid invocation of the CLI tool.
 func UsageExamples() string {
 	return os.Args[0] + ` health liveness` + "\n" +
-		os.Args[0] + ` task create --body "Eaque excepturi suscipit veritatis nemo." --task-name "Corrupti facere sequi tempora eius assumenda molestiae." --cache-namespace "Laborum sapiente." --cache-scope "Nam et."` + "\n" +
+		os.Args[0] + ` task create --body "Ipsam et est accusantium." --task-name "Corrupti quia autem dolorum sunt aperiam quaerat." --cache-namespace "Eveniet et eligendi sint quibusdam quia maxime." --cache-scope "Et ipsa voluptate."` + "\n" +
+		os.Args[0] + ` task-list create --body "Rerum quod error est esse nisi." --task-list-name "Sapiente et." --cache-namespace "Delectus natus eos." --cache-scope "Quae ut dolores ab."` + "\n" +
 		""
 }
 
@@ -62,6 +65,14 @@ func ParseEndpoint(
 
 		taskTaskResultFlags      = flag.NewFlagSet("task-result", flag.ExitOnError)
 		taskTaskResultTaskIDFlag = taskTaskResultFlags.String("task-id", "REQUIRED", "Unique task identifier.")
+
+		taskListFlags = flag.NewFlagSet("task-list", flag.ContinueOnError)
+
+		taskListCreateFlags              = flag.NewFlagSet("create", flag.ExitOnError)
+		taskListCreateBodyFlag           = taskListCreateFlags.String("body", "REQUIRED", "")
+		taskListCreateTaskListNameFlag   = taskListCreateFlags.String("task-list-name", "REQUIRED", "TaskList name.")
+		taskListCreateCacheNamespaceFlag = taskListCreateFlags.String("cache-namespace", "", "")
+		taskListCreateCacheScopeFlag     = taskListCreateFlags.String("cache-scope", "", "")
 	)
 	healthFlags.Usage = healthUsage
 	healthLivenessFlags.Usage = healthLivenessUsage
@@ -71,6 +82,9 @@ func ParseEndpoint(
 	taskCreateFlags.Usage = taskCreateUsage
 	taskTaskResultFlags.Usage = taskTaskResultUsage
 
+	taskListFlags.Usage = taskListUsage
+	taskListCreateFlags.Usage = taskListCreateUsage
+
 	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
 		return nil, nil, err
 	}
@@ -90,6 +104,8 @@ func ParseEndpoint(
 			svcf = healthFlags
 		case "task":
 			svcf = taskFlags
+		case "task-list":
+			svcf = taskListFlags
 		default:
 			return nil, nil, fmt.Errorf("unknown service %q", svcn)
 		}
@@ -125,6 +141,13 @@ func ParseEndpoint(
 
 			}
 
+		case "task-list":
+			switch epn {
+			case "create":
+				epf = taskListCreateFlags
+
+			}
+
 		}
 	}
 	if epf == nil {
@@ -165,6 +188,13 @@ func ParseEndpoint(
 				endpoint = c.TaskResult()
 				data, err = taskc.BuildTaskResultPayload(*taskTaskResultTaskIDFlag)
 			}
+		case "task-list":
+			c := tasklistc.NewClient(scheme, host, doer, enc, dec, restore)
+			switch epn {
+			case "create":
+				endpoint = c.Create()
+				data, err = tasklistc.BuildCreatePayload(*taskListCreateBodyFlag, *taskListCreateTaskListNameFlag, *taskListCreateCacheNamespaceFlag, *taskListCreateCacheScopeFlag)
+			}
 		}
 	}
 	if err != nil {
@@ -232,7 +262,7 @@ Create a task and put it in a queue for execution.
     -cache-scope STRING: 
 
 Example:
-    %[1]s task create --body "Eaque excepturi suscipit veritatis nemo." --task-name "Corrupti facere sequi tempora eius assumenda molestiae." --cache-namespace "Laborum sapiente." --cache-scope "Nam et."
+    %[1]s task create --body "Ipsam et est accusantium." --task-name "Corrupti quia autem dolorum sunt aperiam quaerat." --cache-namespace "Eveniet et eligendi sint quibusdam quia maxime." --cache-scope "Et ipsa voluptate."
 `, os.Args[0])
 }
 
@@ -243,6 +273,34 @@ TaskResult retrieves task result from the Cache service.
     -task-id STRING: Unique task identifier.
 
 Example:
-    %[1]s task task-result --task-id "Et ipsa voluptate."
+    %[1]s task task-result --task-id "Excepturi aut consequatur animi rerum."
+`, os.Args[0])
+}
+
+// task-listUsage displays the usage of the task-list command and its
+// subcommands.
+func taskListUsage() {
+	fmt.Fprintf(os.Stderr, `TaskList service provides endpoints to work with task lists.
+Usage:
+    %[1]s [globalflags] task-list COMMAND [flags]
+
+COMMAND:
+    create: Create a task list, corresponding groups and tasks and put them in respective queues for execution.
+
+Additional help:
+    %[1]s task-list COMMAND --help
+`, os.Args[0])
+}
+func taskListCreateUsage() {
+	fmt.Fprintf(os.Stderr, `%[1]s [flags] task-list create -body JSON -task-list-name STRING -cache-namespace STRING -cache-scope STRING
+
+Create a task list, corresponding groups and tasks and put them in respective queues for execution.
+    -body JSON: 
+    -task-list-name STRING: TaskList name.
+    -cache-namespace STRING: 
+    -cache-scope STRING: 
+
+Example:
+    %[1]s task-list create --body "Rerum quod error est esse nisi." --task-list-name "Sapiente et." --cache-namespace "Delectus natus eos." --cache-scope "Quae ut dolores ab."
 `, os.Args[0])
 }
diff --git a/gen/http/openapi.json b/gen/http/openapi.json
index 78e36c4475d9a753284914cfcbc51172644ffe72..13e4956be85c69bb6664de4204a7dfbcf60f9db0 100644
--- a/gen/http/openapi.json
+++ b/gen/http/openapi.json
@@ -1 +1 @@
-{"swagger":"2.0","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":""},"host":"localhost:8082","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for task execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskCreateResponseBody","required":["taskID"]}}},"schemes":["http"]}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}},"definitions":{"TaskCreateResponseBody":{"title":"TaskCreateResponseBody","type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Vel odio et doloribus est quod laborum."}},"example":{"taskID":"Harum aut autem aliquam dolorem non soluta."},"required":["taskID"]}}}
\ No newline at end of file
+{"swagger":"2.0","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":""},"host":"localhost:8082","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for task execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskCreateResponseBody","required":["taskID"]}}},"schemes":["http"]}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list, corresponding groups and tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for taskList execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskListCreateResponseBody","required":["taskListID"]}}},"schemes":["http"]}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}},"definitions":{"TaskCreateResponseBody":{"title":"TaskCreateResponseBody","type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Et officiis aut."}},"example":{"taskID":"Atque veritatis."},"required":["taskID"]},"TaskListCreateResponseBody":{"title":"TaskListCreateResponseBody","type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Deserunt dolor et autem quidem fugiat sint."}},"example":{"taskListID":"Aut voluptas possimus quia aliquam sit."},"required":["taskListID"]}}}
\ No newline at end of file
diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml
index 1ccd3b61d33f7ff620ecc4d959899033d4d70ded..b9008d5a089c97a647cc5fb22c831bd7c86a9d92 100644
--- a/gen/http/openapi.yaml
+++ b/gen/http/openapi.yaml
@@ -74,6 +74,46 @@ paths:
             - taskID
       schemes:
       - http
+  /v1/taskList/{taskListName}:
+    post:
+      tags:
+      - taskList
+      summary: Create taskList
+      description: Create a task list, corresponding groups and tasks and put them
+        in respective queues for execution.
+      operationId: taskList#Create
+      parameters:
+      - name: taskListName
+        in: path
+        description: TaskList name.
+        required: true
+        type: string
+      - name: x-cache-namespace
+        in: header
+        description: Cache key namespace
+        required: false
+        type: string
+      - name: x-cache-scope
+        in: header
+        description: Cache key scope
+        required: false
+        type: string
+      - name: any
+        in: body
+        description: Data contains JSON payload that will be used for taskList execution.
+        required: true
+        schema:
+          type: string
+          format: binary
+      responses:
+        "200":
+          description: OK response.
+          schema:
+            $ref: '#/definitions/TaskListCreateResponseBody'
+            required:
+            - taskListID
+      schemes:
+      - http
   /v1/taskResult/{taskID}:
     get:
       tags:
@@ -103,8 +143,20 @@ definitions:
       taskID:
         type: string
         description: Unique task identifier.
-        example: Vel odio et doloribus est quod laborum.
+        example: Et officiis aut.
     example:
-      taskID: Harum aut autem aliquam dolorem non soluta.
+      taskID: Atque veritatis.
     required:
     - taskID
+  TaskListCreateResponseBody:
+    title: TaskListCreateResponseBody
+    type: object
+    properties:
+      taskListID:
+        type: string
+        description: Unique taskList identifier.
+        example: Deserunt dolor et autem quidem fugiat sint.
+    example:
+      taskListID: Aut voluptas possimus quia aliquam sit.
+    required:
+    - taskListID
diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json
index 926387963b08082fda67874bb159f6e86d4c8295..4a39db1b50f4e6ac9185165a43d3ae6c3b14c9f6 100644
--- a/gen/http/openapi3.json
+++ b/gen/http/openapi3.json
@@ -1 +1 @@
-{"openapi":"3.0.3","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":"1.0"},"servers":[{"url":"http://localhost:8082","description":"Task Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"schema":{"type":"string","description":"Task name.","example":"Aut qui aut itaque et commodi vel."},"example":"Sapiente et."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for task execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for task execution.","example":"Excepturi aut consequatur animi rerum.","format":"binary"},"example":"Dolorem illo officiis ipsa impedit harum et."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateResult"},"example":{"taskID":"Corrupti quia autem dolorum sunt aperiam quaerat."}}}}}}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"schema":{"type":"string","description":"Unique task identifier.","example":"Delectus natus eos."},"example":"Quae ut dolores ab."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Illum quidem sapiente sed velit.","format":"binary"},"example":"Omnis commodi reiciendis eum non."}}}}}}},"components":{"schemas":{"CreateResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Dolores atque error ab."}},"example":{"taskID":"Laboriosam perspiciatis vitae numquam."},"required":["taskID"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."}]}
\ No newline at end of file
+{"openapi":"3.0.3","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":"1.0"},"servers":[{"url":"http://localhost:8082","description":"Task Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"schema":{"type":"string","description":"Task name.","example":"Voluptatem iure qui facilis aut."},"example":"Excepturi non."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for task execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for task execution.","example":"Impedit iste suscipit.","format":"binary"},"example":"Excepturi in ex ratione."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskResult"},"example":{"taskID":"Vel odio et doloribus est quod laborum."}}}}}}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list, corresponding groups and tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"schema":{"type":"string","description":"TaskList name.","example":"Incidunt autem eaque."},"example":"Fugit ut eius sint earum."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for taskList execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for taskList execution.","example":"Reiciendis numquam.","format":"binary"},"example":"At consequatur nulla praesentium totam dolores voluptas."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskListResult"},"example":{"taskListID":"Quaerat ut fugit voluptatem dolores deserunt in."}}}}}}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"schema":{"type":"string","description":"Unique task identifier.","example":"Ut et est aut quae magnam."},"example":"Amet sapiente qui non."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Placeat molestias praesentium necessitatibus sed.","format":"binary"},"example":"Sint nulla."}}}}}}},"components":{"schemas":{"CreateTaskListResult":{"type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Doloribus ullam voluptas quos aut tempore."}},"example":{"taskListID":"Porro perspiciatis qui vitae totam eligendi officiis."},"required":["taskListID"]},"CreateTaskResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Facilis distinctio asperiores ut architecto ducimus."}},"example":{"taskID":"Omnis et."},"required":["taskID"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."},{"name":"taskList","description":"TaskList service provides endpoints to work with task lists."}]}
\ No newline at end of file
diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml
index 7822203e80727be6ad349a505c7520f5f53bf1be..3b234d0b2694c25ae7b41a466c4a52329a6b48d7 100644
--- a/gen/http/openapi3.yaml
+++ b/gen/http/openapi3.yaml
@@ -40,8 +40,8 @@ paths:
         schema:
           type: string
           description: Task name.
-          example: Aut qui aut itaque et commodi vel.
-        example: Sapiente et.
+          example: Voluptatem iure qui facilis aut.
+        example: Excepturi non.
       - name: x-cache-namespace
         in: header
         description: Cache key namespace
@@ -68,18 +68,75 @@ paths:
             schema:
               type: string
               description: Data contains JSON payload that will be used for task execution.
-              example: Excepturi aut consequatur animi rerum.
+              example: Impedit iste suscipit.
               format: binary
-            example: Dolorem illo officiis ipsa impedit harum et.
+            example: Excepturi in ex ratione.
       responses:
         "200":
           description: OK response.
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/CreateResult'
+                $ref: '#/components/schemas/CreateTaskResult'
               example:
-                taskID: Corrupti quia autem dolorum sunt aperiam quaerat.
+                taskID: Vel odio et doloribus est quod laborum.
+  /v1/taskList/{taskListName}:
+    post:
+      tags:
+      - taskList
+      summary: Create taskList
+      description: Create a task list, corresponding groups and tasks and put them
+        in respective queues for execution.
+      operationId: taskList#Create
+      parameters:
+      - name: taskListName
+        in: path
+        description: TaskList name.
+        required: true
+        schema:
+          type: string
+          description: TaskList name.
+          example: Incidunt autem eaque.
+        example: Fugit ut eius sint earum.
+      - name: x-cache-namespace
+        in: header
+        description: Cache key namespace
+        allowEmptyValue: true
+        schema:
+          type: string
+          description: Cache key namespace
+          example: login
+        example: login
+      - name: x-cache-scope
+        in: header
+        description: Cache key scope
+        allowEmptyValue: true
+        schema:
+          type: string
+          description: Cache key scope
+          example: user
+        example: user
+      requestBody:
+        description: Data contains JSON payload that will be used for taskList execution.
+        required: true
+        content:
+          application/json:
+            schema:
+              type: string
+              description: Data contains JSON payload that will be used for taskList
+                execution.
+              example: Reiciendis numquam.
+              format: binary
+            example: At consequatur nulla praesentium totam dolores voluptas.
+      responses:
+        "200":
+          description: OK response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/CreateTaskListResult'
+              example:
+                taskListID: Quaerat ut fugit voluptatem dolores deserunt in.
   /v1/taskResult/{taskID}:
     get:
       tags:
@@ -95,8 +152,8 @@ paths:
         schema:
           type: string
           description: Unique task identifier.
-          example: Delectus natus eos.
-        example: Quae ut dolores ab.
+          example: Ut et est aut quae magnam.
+        example: Amet sapiente qui non.
       responses:
         "200":
           description: OK response.
@@ -104,20 +161,31 @@ paths:
             application/json:
               schema:
                 type: string
-                example: Illum quidem sapiente sed velit.
+                example: Placeat molestias praesentium necessitatibus sed.
                 format: binary
-              example: Omnis commodi reiciendis eum non.
+              example: Sint nulla.
 components:
   schemas:
-    CreateResult:
+    CreateTaskListResult:
+      type: object
+      properties:
+        taskListID:
+          type: string
+          description: Unique taskList identifier.
+          example: Doloribus ullam voluptas quos aut tempore.
+      example:
+        taskListID: Porro perspiciatis qui vitae totam eligendi officiis.
+      required:
+      - taskListID
+    CreateTaskResult:
       type: object
       properties:
         taskID:
           type: string
           description: Unique task identifier.
-          example: Dolores atque error ab.
+          example: Facilis distinctio asperiores ut architecto ducimus.
       example:
-        taskID: Laboriosam perspiciatis vitae numquam.
+        taskID: Omnis et.
       required:
       - taskID
 tags:
@@ -125,3 +193,5 @@ tags:
   description: Health service provides health check endpoints.
 - name: task
   description: Task service provides endpoints to work with tasks.
+- name: taskList
+  description: TaskList service provides endpoints to work with task lists.
diff --git a/gen/http/task/client/cli.go b/gen/http/task/client/cli.go
index f4e478f9179ff782d6cf169ef51804e1f7d6eed9..3080e4ebc945b6f4f29af532b072a18c0ad3094c 100644
--- a/gen/http/task/client/cli.go
+++ b/gen/http/task/client/cli.go
@@ -16,13 +16,13 @@ import (
 
 // BuildCreatePayload builds the payload for the task Create endpoint from CLI
 // flags.
-func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCreateCacheNamespace string, taskCreateCacheScope string) (*task.CreateRequest, error) {
+func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCreateCacheNamespace string, taskCreateCacheScope string) (*task.CreateTaskRequest, error) {
 	var err error
 	var body interface{}
 	{
 		err = json.Unmarshal([]byte(taskCreateBody), &body)
 		if err != nil {
-			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Eaque excepturi suscipit veritatis nemo.\"")
+			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Ipsam et est accusantium.\"")
 		}
 	}
 	var taskName string
@@ -42,7 +42,7 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr
 		}
 	}
 	v := body
-	res := &task.CreateRequest{
+	res := &task.CreateTaskRequest{
 		Data: v,
 	}
 	res.TaskName = taskName
diff --git a/gen/http/task/client/encode_decode.go b/gen/http/task/client/encode_decode.go
index a7ecbf5caea14083c7bcfdac4483920e08fa1835..1fd5f926ececb598eb85c0a940cc1090d0577690 100644
--- a/gen/http/task/client/encode_decode.go
+++ b/gen/http/task/client/encode_decode.go
@@ -25,9 +25,9 @@ func (c *Client) BuildCreateRequest(ctx context.Context, v interface{}) (*http.R
 		taskName string
 	)
 	{
-		p, ok := v.(*task.CreateRequest)
+		p, ok := v.(*task.CreateTaskRequest)
 		if !ok {
-			return nil, goahttp.ErrInvalidType("task", "Create", "*task.CreateRequest", v)
+			return nil, goahttp.ErrInvalidType("task", "Create", "*task.CreateTaskRequest", v)
 		}
 		taskName = p.TaskName
 	}
@@ -47,9 +47,9 @@ func (c *Client) BuildCreateRequest(ctx context.Context, v interface{}) (*http.R
 // server.
 func EncodeCreateRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error {
 	return func(req *http.Request, v interface{}) error {
-		p, ok := v.(*task.CreateRequest)
+		p, ok := v.(*task.CreateTaskRequest)
 		if !ok {
-			return goahttp.ErrInvalidType("task", "Create", "*task.CreateRequest", v)
+			return goahttp.ErrInvalidType("task", "Create", "*task.CreateTaskRequest", v)
 		}
 		if p.CacheNamespace != nil {
 			head := *p.CacheNamespace
@@ -98,7 +98,7 @@ func DecodeCreateResponse(decoder func(*http.Response) goahttp.Decoder, restoreB
 			if err != nil {
 				return nil, goahttp.ErrValidationError("task", "Create", err)
 			}
-			res := NewCreateResultOK(&body)
+			res := NewCreateTaskResultOK(&body)
 			return res, nil
 		default:
 			body, _ := ioutil.ReadAll(resp.Body)
diff --git a/gen/http/task/client/types.go b/gen/http/task/client/types.go
index 7f5244d65480df67bf86504d92affb4d836124ae..2b4b14fee01e71ca55048514cafe37f945455e33 100644
--- a/gen/http/task/client/types.go
+++ b/gen/http/task/client/types.go
@@ -19,10 +19,10 @@ type CreateResponseBody struct {
 	TaskID *string `form:"taskID,omitempty" json:"taskID,omitempty" xml:"taskID,omitempty"`
 }
 
-// NewCreateResultOK builds a "task" service "Create" endpoint result from a
-// HTTP "OK" response.
-func NewCreateResultOK(body *CreateResponseBody) *task.CreateResult {
-	v := &task.CreateResult{
+// NewCreateTaskResultOK builds a "task" service "Create" endpoint result from
+// a HTTP "OK" response.
+func NewCreateTaskResultOK(body *CreateResponseBody) *task.CreateTaskResult {
+	v := &task.CreateTaskResult{
 		TaskID: *body.TaskID,
 	}
 
diff --git a/gen/http/task/server/encode_decode.go b/gen/http/task/server/encode_decode.go
index 716de0ada1b13cec9bb4401ef6e06a8ec19b3a26..309b093acd6f4ed65e7126e9d0dee1af70c33574 100644
--- a/gen/http/task/server/encode_decode.go
+++ b/gen/http/task/server/encode_decode.go
@@ -21,7 +21,7 @@ import (
 // Create endpoint.
 func EncodeCreateResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error {
 	return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
-		res, _ := v.(*task.CreateResult)
+		res, _ := v.(*task.CreateTaskResult)
 		enc := encoder(ctx, w)
 		body := NewCreateResponseBody(res)
 		w.WriteHeader(http.StatusOK)
@@ -61,7 +61,7 @@ func DecodeCreateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.
 		if cacheScopeRaw != "" {
 			cacheScope = &cacheScopeRaw
 		}
-		payload := NewCreateRequest(body, taskName, cacheNamespace, cacheScope)
+		payload := NewCreateTaskRequest(body, taskName, cacheNamespace, cacheScope)
 
 		return payload, nil
 	}
diff --git a/gen/http/task/server/types.go b/gen/http/task/server/types.go
index c1482c9a8bc09f8781fd87e399293afa5c4392c6..b5a3db61fe4375f8ab37e32ec2d46a279144f211 100644
--- a/gen/http/task/server/types.go
+++ b/gen/http/task/server/types.go
@@ -20,17 +20,17 @@ type CreateResponseBody struct {
 
 // NewCreateResponseBody builds the HTTP response body from the result of the
 // "Create" endpoint of the "task" service.
-func NewCreateResponseBody(res *task.CreateResult) *CreateResponseBody {
+func NewCreateResponseBody(res *task.CreateTaskResult) *CreateResponseBody {
 	body := &CreateResponseBody{
 		TaskID: res.TaskID,
 	}
 	return body
 }
 
-// NewCreateRequest builds a task service Create endpoint payload.
-func NewCreateRequest(body interface{}, taskName string, cacheNamespace *string, cacheScope *string) *task.CreateRequest {
+// NewCreateTaskRequest builds a task service Create endpoint payload.
+func NewCreateTaskRequest(body interface{}, taskName string, cacheNamespace *string, cacheScope *string) *task.CreateTaskRequest {
 	v := body
-	res := &task.CreateRequest{
+	res := &task.CreateTaskRequest{
 		Data: v,
 	}
 	res.TaskName = taskName
diff --git a/gen/http/task_list/client/cli.go b/gen/http/task_list/client/cli.go
new file mode 100644
index 0000000000000000000000000000000000000000..a46f7e6b65abf426b31ebafbdd65df0c52b216a8
--- /dev/null
+++ b/gen/http/task_list/client/cli.go
@@ -0,0 +1,53 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP client CLI support package
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+)
+
+// BuildCreatePayload builds the payload for the taskList Create endpoint from
+// CLI flags.
+func BuildCreatePayload(taskListCreateBody string, taskListCreateTaskListName string, taskListCreateCacheNamespace string, taskListCreateCacheScope string) (*tasklist.CreateTaskListRequest, error) {
+	var err error
+	var body interface{}
+	{
+		err = json.Unmarshal([]byte(taskListCreateBody), &body)
+		if err != nil {
+			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Rerum quod error est esse nisi.\"")
+		}
+	}
+	var taskListName string
+	{
+		taskListName = taskListCreateTaskListName
+	}
+	var cacheNamespace *string
+	{
+		if taskListCreateCacheNamespace != "" {
+			cacheNamespace = &taskListCreateCacheNamespace
+		}
+	}
+	var cacheScope *string
+	{
+		if taskListCreateCacheScope != "" {
+			cacheScope = &taskListCreateCacheScope
+		}
+	}
+	v := body
+	res := &tasklist.CreateTaskListRequest{
+		Data: v,
+	}
+	res.TaskListName = taskListName
+	res.CacheNamespace = cacheNamespace
+	res.CacheScope = cacheScope
+
+	return res, nil
+}
diff --git a/gen/http/task_list/client/client.go b/gen/http/task_list/client/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..7beb029b37d637bc6fc7ca2249ee7a84e2d100fe
--- /dev/null
+++ b/gen/http/task_list/client/client.go
@@ -0,0 +1,74 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList client HTTP transport
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package client
+
+import (
+	"context"
+	"net/http"
+
+	goahttp "goa.design/goa/v3/http"
+	goa "goa.design/goa/v3/pkg"
+)
+
+// Client lists the taskList service endpoint HTTP clients.
+type Client struct {
+	// Create Doer is the HTTP client used to make requests to the Create endpoint.
+	CreateDoer goahttp.Doer
+
+	// RestoreResponseBody controls whether the response bodies are reset after
+	// decoding so they can be read again.
+	RestoreResponseBody bool
+
+	scheme  string
+	host    string
+	encoder func(*http.Request) goahttp.Encoder
+	decoder func(*http.Response) goahttp.Decoder
+}
+
+// NewClient instantiates HTTP clients for all the taskList service servers.
+func NewClient(
+	scheme string,
+	host string,
+	doer goahttp.Doer,
+	enc func(*http.Request) goahttp.Encoder,
+	dec func(*http.Response) goahttp.Decoder,
+	restoreBody bool,
+) *Client {
+	return &Client{
+		CreateDoer:          doer,
+		RestoreResponseBody: restoreBody,
+		scheme:              scheme,
+		host:                host,
+		decoder:             dec,
+		encoder:             enc,
+	}
+}
+
+// Create returns an endpoint that makes HTTP requests to the taskList service
+// Create server.
+func (c *Client) Create() goa.Endpoint {
+	var (
+		encodeRequest  = EncodeCreateRequest(c.encoder)
+		decodeResponse = DecodeCreateResponse(c.decoder, c.RestoreResponseBody)
+	)
+	return func(ctx context.Context, v interface{}) (interface{}, error) {
+		req, err := c.BuildCreateRequest(ctx, v)
+		if err != nil {
+			return nil, err
+		}
+		err = encodeRequest(req, v)
+		if err != nil {
+			return nil, err
+		}
+		resp, err := c.CreateDoer.Do(req)
+		if err != nil {
+			return nil, goahttp.ErrRequestError("taskList", "Create", err)
+		}
+		return decodeResponse(resp)
+	}
+}
diff --git a/gen/http/task_list/client/encode_decode.go b/gen/http/task_list/client/encode_decode.go
new file mode 100644
index 0000000000000000000000000000000000000000..a8c5892c07ad6acdd709ff1f6875b1138eba762a
--- /dev/null
+++ b/gen/http/task_list/client/encode_decode.go
@@ -0,0 +1,108 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP client encoders and decoders
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package client
+
+import (
+	"bytes"
+	"context"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	goahttp "goa.design/goa/v3/http"
+)
+
+// BuildCreateRequest instantiates a HTTP request object with method and path
+// set to call the "taskList" service "Create" endpoint
+func (c *Client) BuildCreateRequest(ctx context.Context, v interface{}) (*http.Request, error) {
+	var (
+		taskListName string
+	)
+	{
+		p, ok := v.(*tasklist.CreateTaskListRequest)
+		if !ok {
+			return nil, goahttp.ErrInvalidType("taskList", "Create", "*tasklist.CreateTaskListRequest", v)
+		}
+		taskListName = p.TaskListName
+	}
+	u := &url.URL{Scheme: c.scheme, Host: c.host, Path: CreateTaskListPath(taskListName)}
+	req, err := http.NewRequest("POST", u.String(), nil)
+	if err != nil {
+		return nil, goahttp.ErrInvalidURL("taskList", "Create", u.String(), err)
+	}
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	return req, nil
+}
+
+// EncodeCreateRequest returns an encoder for requests sent to the taskList
+// Create server.
+func EncodeCreateRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error {
+	return func(req *http.Request, v interface{}) error {
+		p, ok := v.(*tasklist.CreateTaskListRequest)
+		if !ok {
+			return goahttp.ErrInvalidType("taskList", "Create", "*tasklist.CreateTaskListRequest", v)
+		}
+		if p.CacheNamespace != nil {
+			head := *p.CacheNamespace
+			req.Header.Set("x-cache-namespace", head)
+		}
+		if p.CacheScope != nil {
+			head := *p.CacheScope
+			req.Header.Set("x-cache-scope", head)
+		}
+		body := p.Data
+		if err := encoder(req).Encode(&body); err != nil {
+			return goahttp.ErrEncodingError("taskList", "Create", err)
+		}
+		return nil
+	}
+}
+
+// DecodeCreateResponse returns a decoder for responses returned by the
+// taskList Create endpoint. restoreBody controls whether the response body
+// should be restored after having been read.
+func DecodeCreateResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) {
+	return func(resp *http.Response) (interface{}, error) {
+		if restoreBody {
+			b, err := ioutil.ReadAll(resp.Body)
+			if err != nil {
+				return nil, err
+			}
+			resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+			defer func() {
+				resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+			}()
+		} else {
+			defer resp.Body.Close()
+		}
+		switch resp.StatusCode {
+		case http.StatusOK:
+			var (
+				body CreateResponseBody
+				err  error
+			)
+			err = decoder(resp).Decode(&body)
+			if err != nil {
+				return nil, goahttp.ErrDecodingError("taskList", "Create", err)
+			}
+			err = ValidateCreateResponseBody(&body)
+			if err != nil {
+				return nil, goahttp.ErrValidationError("taskList", "Create", err)
+			}
+			res := NewCreateTaskListResultOK(&body)
+			return res, nil
+		default:
+			body, _ := ioutil.ReadAll(resp.Body)
+			return nil, goahttp.ErrInvalidResponse("taskList", "Create", resp.StatusCode, string(body))
+		}
+	}
+}
diff --git a/gen/http/task_list/client/paths.go b/gen/http/task_list/client/paths.go
new file mode 100644
index 0000000000000000000000000000000000000000..ce764600818ffe4a5a0df13ee8cdd75e3db92428
--- /dev/null
+++ b/gen/http/task_list/client/paths.go
@@ -0,0 +1,17 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// HTTP request path constructors for the taskList service.
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package client
+
+import (
+	"fmt"
+)
+
+// CreateTaskListPath returns the URL path to the taskList service Create HTTP endpoint.
+func CreateTaskListPath(taskListName string) string {
+	return fmt.Sprintf("/v1/taskList/%v", taskListName)
+}
diff --git a/gen/http/task_list/client/types.go b/gen/http/task_list/client/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..902273026c2e1b2237fc0b70252f96669b7e42c1
--- /dev/null
+++ b/gen/http/task_list/client/types.go
@@ -0,0 +1,38 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP client types
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package client
+
+import (
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	goa "goa.design/goa/v3/pkg"
+)
+
+// CreateResponseBody is the type of the "taskList" service "Create" endpoint
+// HTTP response body.
+type CreateResponseBody struct {
+	// Unique taskList identifier.
+	TaskListID *string `form:"taskListID,omitempty" json:"taskListID,omitempty" xml:"taskListID,omitempty"`
+}
+
+// NewCreateTaskListResultOK builds a "taskList" service "Create" endpoint
+// result from a HTTP "OK" response.
+func NewCreateTaskListResultOK(body *CreateResponseBody) *tasklist.CreateTaskListResult {
+	v := &tasklist.CreateTaskListResult{
+		TaskListID: *body.TaskListID,
+	}
+
+	return v
+}
+
+// ValidateCreateResponseBody runs the validations defined on CreateResponseBody
+func ValidateCreateResponseBody(body *CreateResponseBody) (err error) {
+	if body.TaskListID == nil {
+		err = goa.MergeErrors(err, goa.MissingFieldError("taskListID", "body"))
+	}
+	return
+}
diff --git a/gen/http/task_list/server/encode_decode.go b/gen/http/task_list/server/encode_decode.go
new file mode 100644
index 0000000000000000000000000000000000000000..be27fbb71c3e3e8a5cfc1859b3aabb3352be4fab
--- /dev/null
+++ b/gen/http/task_list/server/encode_decode.go
@@ -0,0 +1,68 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP server encoders and decoders
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package server
+
+import (
+	"context"
+	"io"
+	"net/http"
+
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	goahttp "goa.design/goa/v3/http"
+	goa "goa.design/goa/v3/pkg"
+)
+
+// EncodeCreateResponse returns an encoder for responses returned by the
+// taskList Create endpoint.
+func EncodeCreateResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error {
+	return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
+		res, _ := v.(*tasklist.CreateTaskListResult)
+		enc := encoder(ctx, w)
+		body := NewCreateResponseBody(res)
+		w.WriteHeader(http.StatusOK)
+		return enc.Encode(body)
+	}
+}
+
+// DecodeCreateRequest returns a decoder for requests sent to the taskList
+// Create endpoint.
+func DecodeCreateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) {
+	return func(r *http.Request) (interface{}, error) {
+		var (
+			body interface{}
+			err  error
+		)
+		err = decoder(r).Decode(&body)
+		if err != nil {
+			if err == io.EOF {
+				return nil, goa.MissingPayloadError()
+			}
+			return nil, goa.DecodePayloadError(err.Error())
+		}
+
+		var (
+			taskListName   string
+			cacheNamespace *string
+			cacheScope     *string
+
+			params = mux.Vars(r)
+		)
+		taskListName = params["taskListName"]
+		cacheNamespaceRaw := r.Header.Get("x-cache-namespace")
+		if cacheNamespaceRaw != "" {
+			cacheNamespace = &cacheNamespaceRaw
+		}
+		cacheScopeRaw := r.Header.Get("x-cache-scope")
+		if cacheScopeRaw != "" {
+			cacheScope = &cacheScopeRaw
+		}
+		payload := NewCreateTaskListRequest(body, taskListName, cacheNamespace, cacheScope)
+
+		return payload, nil
+	}
+}
diff --git a/gen/http/task_list/server/paths.go b/gen/http/task_list/server/paths.go
new file mode 100644
index 0000000000000000000000000000000000000000..80662ac5bb501534cf2f22138127b98eb86bcece
--- /dev/null
+++ b/gen/http/task_list/server/paths.go
@@ -0,0 +1,17 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// HTTP request path constructors for the taskList service.
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package server
+
+import (
+	"fmt"
+)
+
+// CreateTaskListPath returns the URL path to the taskList service Create HTTP endpoint.
+func CreateTaskListPath(taskListName string) string {
+	return fmt.Sprintf("/v1/taskList/%v", taskListName)
+}
diff --git a/gen/http/task_list/server/server.go b/gen/http/task_list/server/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..4d4d72dcec6b49130f5823ceb8148687eb4ccab0
--- /dev/null
+++ b/gen/http/task_list/server/server.go
@@ -0,0 +1,131 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP server
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package server
+
+import (
+	"context"
+	"net/http"
+
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	goahttp "goa.design/goa/v3/http"
+	goa "goa.design/goa/v3/pkg"
+)
+
+// Server lists the taskList service endpoint HTTP handlers.
+type Server struct {
+	Mounts []*MountPoint
+	Create http.Handler
+}
+
+// ErrorNamer is an interface implemented by generated error structs that
+// exposes the name of the error as defined in the design.
+type ErrorNamer interface {
+	ErrorName() string
+}
+
+// MountPoint holds information about the mounted endpoints.
+type MountPoint struct {
+	// Method is the name of the service method served by the mounted HTTP handler.
+	Method string
+	// Verb is the HTTP method used to match requests to the mounted handler.
+	Verb string
+	// Pattern is the HTTP request path pattern used to match requests to the
+	// mounted handler.
+	Pattern string
+}
+
+// New instantiates HTTP handlers for all the taskList service endpoints using
+// the provided encoder and decoder. The handlers are mounted on the given mux
+// using the HTTP verb and path defined in the design. errhandler is called
+// whenever a response fails to be encoded. formatter is used to format errors
+// returned by the service methods prior to encoding. Both errhandler and
+// formatter are optional and can be nil.
+func New(
+	e *tasklist.Endpoints,
+	mux goahttp.Muxer,
+	decoder func(*http.Request) goahttp.Decoder,
+	encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
+	errhandler func(context.Context, http.ResponseWriter, error),
+	formatter func(err error) goahttp.Statuser,
+) *Server {
+	return &Server{
+		Mounts: []*MountPoint{
+			{"Create", "POST", "/v1/taskList/{taskListName}"},
+		},
+		Create: NewCreateHandler(e.Create, mux, decoder, encoder, errhandler, formatter),
+	}
+}
+
+// Service returns the name of the service served.
+func (s *Server) Service() string { return "taskList" }
+
+// Use wraps the server handlers with the given middleware.
+func (s *Server) Use(m func(http.Handler) http.Handler) {
+	s.Create = m(s.Create)
+}
+
+// Mount configures the mux to serve the taskList endpoints.
+func Mount(mux goahttp.Muxer, h *Server) {
+	MountCreateHandler(mux, h.Create)
+}
+
+// Mount configures the mux to serve the taskList endpoints.
+func (s *Server) Mount(mux goahttp.Muxer) {
+	Mount(mux, s)
+}
+
+// MountCreateHandler configures the mux to serve the "taskList" service
+// "Create" endpoint.
+func MountCreateHandler(mux goahttp.Muxer, h http.Handler) {
+	f, ok := h.(http.HandlerFunc)
+	if !ok {
+		f = func(w http.ResponseWriter, r *http.Request) {
+			h.ServeHTTP(w, r)
+		}
+	}
+	mux.Handle("POST", "/v1/taskList/{taskListName}", f)
+}
+
+// NewCreateHandler creates a HTTP handler which loads the HTTP request and
+// calls the "taskList" service "Create" endpoint.
+func NewCreateHandler(
+	endpoint goa.Endpoint,
+	mux goahttp.Muxer,
+	decoder func(*http.Request) goahttp.Decoder,
+	encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
+	errhandler func(context.Context, http.ResponseWriter, error),
+	formatter func(err error) goahttp.Statuser,
+) http.Handler {
+	var (
+		decodeRequest  = DecodeCreateRequest(mux, decoder)
+		encodeResponse = EncodeCreateResponse(encoder)
+		encodeError    = goahttp.ErrorEncoder(encoder, formatter)
+	)
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept"))
+		ctx = context.WithValue(ctx, goa.MethodKey, "Create")
+		ctx = context.WithValue(ctx, goa.ServiceKey, "taskList")
+		payload, err := decodeRequest(r)
+		if err != nil {
+			if err := encodeError(ctx, w, err); err != nil {
+				errhandler(ctx, w, err)
+			}
+			return
+		}
+		res, err := endpoint(ctx, payload)
+		if err != nil {
+			if err := encodeError(ctx, w, err); err != nil {
+				errhandler(ctx, w, err)
+			}
+			return
+		}
+		if err := encodeResponse(ctx, w, res); err != nil {
+			errhandler(ctx, w, err)
+		}
+	})
+}
diff --git a/gen/http/task_list/server/types.go b/gen/http/task_list/server/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..879b0a1fa38948d6d92357413004176b75adea8c
--- /dev/null
+++ b/gen/http/task_list/server/types.go
@@ -0,0 +1,41 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList HTTP server types
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package server
+
+import (
+	tasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+)
+
+// CreateResponseBody is the type of the "taskList" service "Create" endpoint
+// HTTP response body.
+type CreateResponseBody struct {
+	// Unique taskList identifier.
+	TaskListID string `form:"taskListID" json:"taskListID" xml:"taskListID"`
+}
+
+// NewCreateResponseBody builds the HTTP response body from the result of the
+// "Create" endpoint of the "taskList" service.
+func NewCreateResponseBody(res *tasklist.CreateTaskListResult) *CreateResponseBody {
+	body := &CreateResponseBody{
+		TaskListID: res.TaskListID,
+	}
+	return body
+}
+
+// NewCreateTaskListRequest builds a taskList service Create endpoint payload.
+func NewCreateTaskListRequest(body interface{}, taskListName string, cacheNamespace *string, cacheScope *string) *tasklist.CreateTaskListRequest {
+	v := body
+	res := &tasklist.CreateTaskListRequest{
+		Data: v,
+	}
+	res.TaskListName = taskListName
+	res.CacheNamespace = cacheNamespace
+	res.CacheScope = cacheScope
+
+	return res
+}
diff --git a/gen/task/client.go b/gen/task/client.go
index 3f812485b1c4b9ff706e6278e0bb385f7f4da636..55b4c3000e146d898a66155c3092df2732eee219 100644
--- a/gen/task/client.go
+++ b/gen/task/client.go
@@ -28,13 +28,13 @@ func NewClient(create, taskResult goa.Endpoint) *Client {
 }
 
 // Create calls the "Create" endpoint of the "task" service.
-func (c *Client) Create(ctx context.Context, p *CreateRequest) (res *CreateResult, err error) {
+func (c *Client) Create(ctx context.Context, p *CreateTaskRequest) (res *CreateTaskResult, err error) {
 	var ires interface{}
 	ires, err = c.CreateEndpoint(ctx, p)
 	if err != nil {
 		return
 	}
-	return ires.(*CreateResult), nil
+	return ires.(*CreateTaskResult), nil
 }
 
 // TaskResult calls the "TaskResult" endpoint of the "task" service.
diff --git a/gen/task/endpoints.go b/gen/task/endpoints.go
index b648dd83cb34f626e54dbfba734439cbfbe813ca..5ea36902f9d0493c4337209bcb40a9899537111e 100644
--- a/gen/task/endpoints.go
+++ b/gen/task/endpoints.go
@@ -37,7 +37,7 @@ func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) {
 // "Create" of service "task".
 func NewCreateEndpoint(s Service) goa.Endpoint {
 	return func(ctx context.Context, req interface{}) (interface{}, error) {
-		p := req.(*CreateRequest)
+		p := req.(*CreateTaskRequest)
 		return s.Create(ctx, p)
 	}
 }
diff --git a/gen/task/service.go b/gen/task/service.go
index f5c4b6954680960745e92c7556d1f243413b7647..81ff7d1ff5b93eb7cb3b05e00d55b30cfbefa0f1 100644
--- a/gen/task/service.go
+++ b/gen/task/service.go
@@ -14,7 +14,7 @@ import (
 // Task service provides endpoints to work with tasks.
 type Service interface {
 	// Create a task and put it in a queue for execution.
-	Create(context.Context, *CreateRequest) (res *CreateResult, err error)
+	Create(context.Context, *CreateTaskRequest) (res *CreateTaskResult, err error)
 	// TaskResult retrieves task result from the Cache service.
 	TaskResult(context.Context, *TaskResultRequest) (res interface{}, err error)
 }
@@ -29,8 +29,8 @@ const ServiceName = "task"
 // MethodKey key.
 var MethodNames = [2]string{"Create", "TaskResult"}
 
-// CreateRequest is the payload type of the task service Create method.
-type CreateRequest struct {
+// CreateTaskRequest is the payload type of the task service Create method.
+type CreateTaskRequest struct {
 	// Task name.
 	TaskName string
 	// Data contains JSON payload that will be used for task execution.
@@ -41,8 +41,8 @@ type CreateRequest struct {
 	CacheScope *string
 }
 
-// CreateResult is the result type of the task service Create method.
-type CreateResult struct {
+// CreateTaskResult is the result type of the task service Create method.
+type CreateTaskResult struct {
 	// Unique task identifier.
 	TaskID string
 }
diff --git a/gen/task_list/client.go b/gen/task_list/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..dcaf4ef0bdab346d90e25b0f4773756a72c10f42
--- /dev/null
+++ b/gen/task_list/client.go
@@ -0,0 +1,36 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList client
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package tasklist
+
+import (
+	"context"
+
+	goa "goa.design/goa/v3/pkg"
+)
+
+// Client is the "taskList" service client.
+type Client struct {
+	CreateEndpoint goa.Endpoint
+}
+
+// NewClient initializes a "taskList" service client given the endpoints.
+func NewClient(create goa.Endpoint) *Client {
+	return &Client{
+		CreateEndpoint: create,
+	}
+}
+
+// Create calls the "Create" endpoint of the "taskList" service.
+func (c *Client) Create(ctx context.Context, p *CreateTaskListRequest) (res *CreateTaskListResult, err error) {
+	var ires interface{}
+	ires, err = c.CreateEndpoint(ctx, p)
+	if err != nil {
+		return
+	}
+	return ires.(*CreateTaskListResult), nil
+}
diff --git a/gen/task_list/endpoints.go b/gen/task_list/endpoints.go
new file mode 100644
index 0000000000000000000000000000000000000000..0a2bc0e4b32a0704d6cf429df56fd1c5823cf708
--- /dev/null
+++ b/gen/task_list/endpoints.go
@@ -0,0 +1,40 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList endpoints
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package tasklist
+
+import (
+	"context"
+
+	goa "goa.design/goa/v3/pkg"
+)
+
+// Endpoints wraps the "taskList" service endpoints.
+type Endpoints struct {
+	Create goa.Endpoint
+}
+
+// NewEndpoints wraps the methods of the "taskList" service with endpoints.
+func NewEndpoints(s Service) *Endpoints {
+	return &Endpoints{
+		Create: NewCreateEndpoint(s),
+	}
+}
+
+// Use applies the given middleware to all the "taskList" service endpoints.
+func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) {
+	e.Create = m(e.Create)
+}
+
+// NewCreateEndpoint returns an endpoint function that calls the method
+// "Create" of service "taskList".
+func NewCreateEndpoint(s Service) goa.Endpoint {
+	return func(ctx context.Context, req interface{}) (interface{}, error) {
+		p := req.(*CreateTaskListRequest)
+		return s.Create(ctx, p)
+	}
+}
diff --git a/gen/task_list/service.go b/gen/task_list/service.go
new file mode 100644
index 0000000000000000000000000000000000000000..e7dbf3ae62c41719450b9ba97002b00c184f3fce
--- /dev/null
+++ b/gen/task_list/service.go
@@ -0,0 +1,49 @@
+// Code generated by goa v3.7.0, DO NOT EDIT.
+//
+// taskList service
+//
+// Command:
+// $ goa gen code.vereign.com/gaiax/tsa/task/design
+
+package tasklist
+
+import (
+	"context"
+)
+
+// TaskList service provides endpoints to work with task lists.
+type Service interface {
+	// Create a task list, corresponding groups and tasks and put them in
+	// respective queues for execution.
+	Create(context.Context, *CreateTaskListRequest) (res *CreateTaskListResult, err error)
+}
+
+// ServiceName is the name of the service as defined in the design. This is the
+// same value that is set in the endpoint request contexts under the ServiceKey
+// key.
+const ServiceName = "taskList"
+
+// MethodNames lists the service method names as defined in the design. These
+// are the same values that are set in the endpoint request contexts under the
+// MethodKey key.
+var MethodNames = [1]string{"Create"}
+
+// CreateTaskListRequest is the payload type of the taskList service Create
+// method.
+type CreateTaskListRequest struct {
+	// TaskList name.
+	TaskListName string
+	// Data contains JSON payload that will be used for taskList execution.
+	Data interface{}
+	// Cache key namespace.
+	CacheNamespace *string
+	// Cache key scope.
+	CacheScope *string
+}
+
+// CreateTaskListResult is the result type of the taskList service Create
+// method.
+type CreateTaskListResult struct {
+	// Unique taskList identifier.
+	TaskListID string
+}
diff --git a/internal/service/task/service.go b/internal/service/task/service.go
index a4ea25ad30982f806f5b9f1431107321c9601b9d..c999eace7b3237e631178439158c250bb1b995a5 100644
--- a/internal/service/task/service.go
+++ b/internal/service/task/service.go
@@ -54,7 +54,7 @@ func New(template Storage, queue Queue, cache Cache, logger *zap.Logger) *Servic
 }
 
 // Create a new task and put it in a Queue for later execution.
-func (s *Service) Create(ctx context.Context, req *goatask.CreateRequest) (res *goatask.CreateResult, err error) {
+func (s *Service) Create(ctx context.Context, req *goatask.CreateTaskRequest) (res *goatask.CreateTaskResult, err error) {
 	if req.TaskName == "" {
 		return nil, errors.New(errors.BadRequest, "missing taskName")
 	}
@@ -92,7 +92,7 @@ func (s *Service) Create(ctx context.Context, req *goatask.CreateRequest) (res *
 		return nil, errors.New("failed to create task", err)
 	}
 
-	return &goatask.CreateResult{TaskID: task.ID}, nil
+	return &goatask.CreateTaskResult{TaskID: task.ID}, nil
 }
 
 // TaskResult retrieves task result from the Cache service.
diff --git a/internal/service/task/service_test.go b/internal/service/task/service_test.go
index 70051423452d36b66e184e8d3ea6f28fb504db3b..eef64de7aaf67300f1b19782421cdb3771f14b2b 100644
--- a/internal/service/task/service_test.go
+++ b/internal/service/task/service_test.go
@@ -22,7 +22,7 @@ func TestNew(t *testing.T) {
 func TestService_Create(t *testing.T) {
 	tests := []struct {
 		name    string
-		req     *goatask.CreateRequest
+		req     *goatask.CreateTaskRequest
 		storage *taskfakes.FakeStorage
 		queue   *taskfakes.FakeQueue
 		cache   *taskfakes.FakeCache
@@ -32,13 +32,13 @@ func TestService_Create(t *testing.T) {
 	}{
 		{
 			name:    "empty task name",
-			req:     &goatask.CreateRequest{},
+			req:     &goatask.CreateTaskRequest{},
 			errkind: errors.BadRequest,
 			errtext: "missing taskName",
 		},
 		{
 			name: "task template not found",
-			req:  &goatask.CreateRequest{TaskName: "taskname"},
+			req:  &goatask.CreateTaskRequest{TaskName: "taskname"},
 			storage: &taskfakes.FakeStorage{
 				TaskTemplateStub: func(ctx context.Context, taskName string) (*task.Task, error) {
 					return nil, errors.New(errors.NotFound)
@@ -49,7 +49,7 @@ func TestService_Create(t *testing.T) {
 		},
 		{
 			name: "fail to add task to queue",
-			req:  &goatask.CreateRequest{TaskName: "taskname"},
+			req:  &goatask.CreateTaskRequest{TaskName: "taskname"},
 			storage: &taskfakes.FakeStorage{
 				TaskTemplateStub: func(ctx context.Context, taskName string) (*task.Task, error) {
 					return &task.Task{}, nil
@@ -65,7 +65,7 @@ func TestService_Create(t *testing.T) {
 		},
 		{
 			name: "successfully add task to queue",
-			req:  &goatask.CreateRequest{TaskName: "taskname"},
+			req:  &goatask.CreateTaskRequest{TaskName: "taskname"},
 			storage: &taskfakes.FakeStorage{
 				TaskTemplateStub: func(ctx context.Context, taskName string) (*task.Task, error) {
 					return &task.Task{}, nil
@@ -79,7 +79,7 @@ func TestService_Create(t *testing.T) {
 		},
 		{
 			name: "successfully add task to queue with namespace and scope",
-			req: &goatask.CreateRequest{
+			req: &goatask.CreateTaskRequest{
 				TaskName:       "taskname",
 				CacheNamespace: ptr.String("login"),
 				CacheScope:     ptr.String("user"),
diff --git a/internal/service/task/task.go b/internal/service/task/task.go
index dd53a5175c505258f3822fa0ee6e8cdd57533dd7..e164797533886ed5536fd10de231b92a0f3a0185 100644
--- a/internal/service/task/task.go
+++ b/internal/service/task/task.go
@@ -22,7 +22,7 @@ const (
 
 type Task struct {
 	ID             string    `json:"id"`             // ID is unique task identifier.
-	GroupID        string    `json:"groupID"`        // GroupID is set when the task is part of `task.Group`.
+	GroupID        string    `json:"groupID"`        // GroupID is set when the task is part of `tasklist.Group`.
 	Name           string    `json:"name"`           // Name is used by external callers use to create tasks.
 	State          State     `json:"state"`          // State of the task.
 	URL            string    `json:"url"`            // URL against which the task request will be executed (optional).
@@ -40,17 +40,6 @@ type Task struct {
 	FinishedAt     time.Time `json:"finishedAt"`     // FinishedAt specifies the time when the task is done.
 }
 
-type Group struct {
-	ID          string
-	Tasks       []Task
-	State       State
-	Metadata    interface{} // TODO(penkovski): not yet clear
-	FinalPolicy string
-	CreateTime  time.Time
-	StartTime   time.Time
-	FinishTime  time.Time
-}
-
 // CacheKey constructs the key for storing task result in the cache.
 func (t *Task) CacheKey() string {
 	key := t.ID
diff --git a/internal/service/tasklist/service.go b/internal/service/tasklist/service.go
new file mode 100644
index 0000000000000000000000000000000000000000..9bbeeb4ed9db27d5f10e4315c968b544dd371ae0
--- /dev/null
+++ b/internal/service/tasklist/service.go
@@ -0,0 +1,177 @@
+package tasklist
+
+import (
+	"context"
+	"encoding/json"
+	"time"
+
+	"github.com/google/uuid"
+	"go.uber.org/zap"
+
+	"code.vereign.com/gaiax/tsa/golib/errors"
+	goatasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+)
+
+//go:generate counterfeiter . Storage
+//go:generate counterfeiter . Queue
+
+// Storage for retrieving predefined task templates.
+type Storage interface {
+	TaskListTemplate(ctx context.Context, taskListName string) (*Template, error)
+	TaskTemplates(ctx context.Context, names []string) (map[string]*task.Task, error)
+}
+
+type Queue interface {
+	AddTaskList(ctx context.Context, taskList *TaskList, tasks []*task.Task) error
+}
+
+type Service struct {
+	storage Storage
+	queue   Queue
+
+	logger *zap.Logger
+}
+
+func New(template Storage, queue Queue, logger *zap.Logger) *Service {
+	return &Service{
+		storage: template,
+		queue:   queue,
+		logger:  logger,
+	}
+}
+
+// Create a taskList and corresponding tasks and put them in
+// respective queues for execution.
+func (s *Service) Create(ctx context.Context, req *goatasklist.CreateTaskListRequest) (*goatasklist.CreateTaskListResult, error) {
+	if req.TaskListName == "" {
+		return nil, errors.New(errors.BadRequest, "missing taskListName")
+	}
+
+	logger := s.logger.With(zap.String("taskListName", req.TaskListName))
+
+	// get predefined taskList definition from storage
+	template, err := s.storage.TaskListTemplate(ctx, req.TaskListName)
+	if err != nil {
+		logger.Error("error getting taskList template from storage", zap.Error(err))
+		return nil, err
+	}
+
+	// get predefined task definitions from storage
+	taskTemplates, err := s.storage.TaskTemplates(ctx, taskNamesFromTaskListTemplate(template))
+	if err != nil {
+		logger.Error("error getting task templates from storage")
+		return nil, err
+	}
+
+	taskListRequest, err := json.Marshal(req.Data)
+	if err != nil {
+		logger.Error("error marshaling request data to JSON", zap.Error(err))
+		return nil, errors.New(errors.BadRequest, "error marshaling request data to JSON", err)
+	}
+
+	taskList := &TaskList{
+		ID:             uuid.NewString(),
+		Groups:         createGroups(template),
+		Name:           template.Name,
+		Request:        taskListRequest,
+		CacheScope:     template.CacheScope,
+		CacheNamespace: template.CacheNamespace,
+		State:          task.Created,
+		CreateTime:     time.Now(),
+	}
+
+	// if cache namespace and scope are given, use them instead of the defaults
+	if req.CacheNamespace != nil && *req.CacheNamespace != "" {
+		taskList.CacheNamespace = *req.CacheNamespace
+	}
+	if req.CacheScope != nil && *req.CacheScope != "" {
+		taskList.CacheScope = *req.CacheScope
+	}
+
+	tasks, err := createTasks(taskList, taskTemplates)
+	if err != nil {
+		logger.Error("failed to create tasks for taskList", zap.Error(err))
+		return nil, errors.New("failed to create tasks for taskList", err)
+	}
+
+	if err := s.queue.AddTaskList(ctx, taskList, tasks); err != nil {
+		logger.Error("error adding taskList to queue", zap.Error(err))
+		return nil, errors.New("error adding taskList to queue", err)
+	}
+
+	return &goatasklist.CreateTaskListResult{
+		TaskListID: taskList.ID,
+	}, nil
+}
+
+func createGroups(t *Template) []Group {
+	var groups []Group
+	for _, group := range t.Groups {
+		g := Group{
+			ID:          uuid.NewString(),
+			Execution:   group.Execution,
+			Tasks:       group.Tasks,
+			State:       task.Created,
+			Metadata:    group.Metadata,
+			FinalPolicy: group.FinalPolicy,
+		}
+		groups = append(groups, g)
+	}
+
+	return groups
+}
+
+// createTasks creates task.Task instances out of task templates
+// in order to be added to queue for execution
+func createTasks(t *TaskList, templates map[string]*task.Task) ([]*task.Task, error) {
+	var tasks []*task.Task
+	for _, group := range t.Groups {
+		for _, taskName := range group.Tasks {
+			template, ok := templates[taskName]
+			if !ok {
+				return nil, errors.New(errors.NotFound, "failed to find task template")
+			}
+
+			task := task.Task{
+				ID:             uuid.NewString(),
+				GroupID:        group.ID,
+				Name:           taskName,
+				State:          task.Created,
+				URL:            template.URL,
+				Method:         template.Method,
+				RequestPolicy:  template.RequestPolicy,
+				ResponsePolicy: template.ResponsePolicy,
+				FinalPolicy:    template.FinalPolicy,
+				CacheNamespace: template.CacheNamespace,
+				CacheScope:     template.CacheScope,
+				CreatedAt:      time.Now(),
+			}
+
+			// if cache namespace and scope are set in the taskList, use them instead of the defaults
+			if t.CacheNamespace != "" {
+				task.CacheNamespace = t.CacheNamespace
+			}
+			if t.CacheScope != "" {
+				task.CacheScope = t.CacheScope
+			}
+
+			tasks = append(tasks, &task)
+		}
+	}
+
+	return tasks, nil
+}
+
+// taskNamesFromTaskListTemplate returns the names of all tasks within
+// one taskList template
+func taskNamesFromTaskListTemplate(template *Template) []string {
+	var names []string
+	for _, group := range template.Groups {
+		for _, taskName := range group.Tasks {
+			names = append(names, taskName)
+		}
+	}
+
+	return names
+}
diff --git a/internal/service/tasklist/service_test.go b/internal/service/tasklist/service_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..9dd3b39e39b25076f55f206661264627f2917c07
--- /dev/null
+++ b/internal/service/tasklist/service_test.go
@@ -0,0 +1,140 @@
+package tasklist_test
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"go.uber.org/zap"
+
+	"code.vereign.com/gaiax/tsa/golib/errors"
+	goatasklist "code.vereign.com/gaiax/tsa/task/gen/task_list"
+	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist/tasklistfakes"
+)
+
+func TestNew(t *testing.T) {
+	svc := tasklist.New(nil, nil, zap.NewNop())
+	assert.Implements(t, (*goatasklist.Service)(nil), svc)
+}
+
+func Test_Create(t *testing.T) {
+	tests := []struct {
+		name    string
+		req     *goatasklist.CreateTaskListRequest
+		storage *tasklistfakes.FakeStorage
+		queue   *tasklistfakes.FakeQueue
+
+		errkind errors.Kind
+		errtext string
+	}{
+		{
+			name:    "empty taskList name",
+			req:     &goatasklist.CreateTaskListRequest{},
+			errkind: errors.BadRequest,
+			errtext: "missing taskListName",
+		},
+		{
+			name: "taskList template not found",
+			req:  &goatasklist.CreateTaskListRequest{TaskListName: "taskList name"},
+			storage: &tasklistfakes.FakeStorage{
+				TaskListTemplateStub: func(ctx context.Context, s string) (*tasklist.Template, error) {
+					return nil, errors.New(errors.NotFound)
+				},
+			},
+			errkind: errors.NotFound,
+			errtext: "not found",
+		},
+		{
+			name: "error getting task templates form storage",
+			req:  &goatasklist.CreateTaskListRequest{TaskListName: "taskList name"},
+			storage: &tasklistfakes.FakeStorage{
+				TaskListTemplateStub: func(ctx context.Context, s string) (*tasklist.Template, error) {
+					return &tasklist.Template{}, nil
+				},
+				TaskTemplatesStub: func(ctx context.Context, strings []string) (map[string]*task.Task, error) {
+					return nil, errors.New(errors.Internal, "internal error")
+				},
+			},
+			errkind: errors.Internal,
+			errtext: "internal error",
+		},
+		{
+			name: "error creating tasks for a taskList, task template not found",
+			req:  &goatasklist.CreateTaskListRequest{TaskListName: "taskList name"},
+			storage: &tasklistfakes.FakeStorage{
+				TaskListTemplateStub: func(ctx context.Context, s string) (*tasklist.Template, error) {
+					return &tasklist.Template{
+						Groups: []tasklist.GroupTemplate{
+							{
+								Tasks: []string{"non-existent task template"},
+							},
+						},
+					}, nil
+				},
+				TaskTemplatesStub: func(ctx context.Context, strings []string) (map[string]*task.Task, error) {
+					return map[string]*task.Task{"template": &task.Task{}}, nil
+				},
+			},
+			errkind: errors.NotFound,
+			errtext: "failed to find task template",
+		},
+		{
+			name: "failed to add taskList and tasks to queue",
+			req:  &goatasklist.CreateTaskListRequest{TaskListName: "taskList name"},
+			storage: &tasklistfakes.FakeStorage{
+				TaskListTemplateStub: func(ctx context.Context, s string) (*tasklist.Template, error) {
+					return &tasklist.Template{}, nil
+				},
+				TaskTemplatesStub: func(ctx context.Context, strings []string) (map[string]*task.Task, error) {
+					return map[string]*task.Task{"template": &task.Task{}}, nil
+				},
+			},
+			queue: &tasklistfakes.FakeQueue{
+				AddTaskListStub: func(ctx context.Context, list *tasklist.TaskList, tasks []*task.Task) error {
+					return errors.New("storage error")
+				},
+			},
+			errkind: errors.Unknown,
+			errtext: "storage error",
+		},
+		{
+			name: "successfully add taskList and tasks to queue",
+			req:  &goatasklist.CreateTaskListRequest{TaskListName: "taskList name"},
+			storage: &tasklistfakes.FakeStorage{
+				TaskListTemplateStub: func(ctx context.Context, s string) (*tasklist.Template, error) {
+					return &tasklist.Template{}, nil
+				},
+				TaskTemplatesStub: func(ctx context.Context, strings []string) (map[string]*task.Task, error) {
+					return map[string]*task.Task{"template": &task.Task{}}, nil
+				},
+			},
+			queue: &tasklistfakes.FakeQueue{
+				AddTaskListStub: func(ctx context.Context, list *tasklist.TaskList, tasks []*task.Task) error {
+					return nil
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			svc := tasklist.New(test.storage, test.queue, zap.NewNop())
+			res, err := svc.Create(context.Background(), test.req)
+			if err != nil {
+				assert.NotEmpty(t, test.errtext)
+				e, ok := err.(*errors.Error)
+				assert.True(t, ok)
+				assert.Equal(t, test.errkind, e.Kind)
+				assert.Contains(t, e.Error(), test.errtext)
+				assert.Nil(t, res)
+			} else {
+				assert.Empty(t, test.errtext)
+				assert.NotNil(t, res)
+				assert.NotEmpty(t, res.TaskListID)
+			}
+
+		})
+	}
+}
diff --git a/internal/service/tasklist/task_list.go b/internal/service/tasklist/task_list.go
new file mode 100644
index 0000000000000000000000000000000000000000..0e3e7f542972d3c531e55225f5a8a39f4dc2c851
--- /dev/null
+++ b/internal/service/tasklist/task_list.go
@@ -0,0 +1,43 @@
+package tasklist
+
+import (
+	"time"
+
+	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+)
+
+type Template struct {
+	Name           string          `json:"name"`
+	CacheNamespace string          `json:"cacheNamespace"`
+	CacheScope     string          `json:"cacheScope"`
+	Groups         []GroupTemplate `json:"groups"`
+}
+
+type GroupTemplate struct {
+	Execution   string      `json:"execution"`
+	FinalPolicy string      `json:"finalPolicy"`
+	Tasks       []string    `json:"tasks"`
+	Metadata    interface{} `json:"metadata"`
+}
+
+type TaskList struct {
+	ID             string     `json:"id"`
+	Name           string     `json:"name"`
+	State          task.State `json:"state"`
+	Groups         []Group    `json:"groups"`
+	Request        []byte     `json:"request"`
+	CacheNamespace string     `json:"cacheNamespace"`
+	CacheScope     string     `json:"cacheScope"`
+	CreateTime     time.Time  `json:"createdAt"`
+	StartTime      time.Time  `json:"startedAt"`
+	FinishTime     time.Time  `json:"finishedAt"`
+}
+
+type Group struct {
+	ID          string      `json:"id"`
+	Execution   string      `json:"execution"`
+	Tasks       []string    `json:"tasks"`
+	State       task.State  `json:"state"`
+	Metadata    interface{} `json:"metadata"` // TODO(penkovski): not yet clear
+	FinalPolicy string      `json:"finalPolicy"`
+}
diff --git a/internal/service/tasklist/tasklistfakes/fake_queue.go b/internal/service/tasklist/tasklistfakes/fake_queue.go
new file mode 100644
index 0000000000000000000000000000000000000000..75e572da1f1ea976808a9028be753d94b936f132
--- /dev/null
+++ b/internal/service/tasklist/tasklistfakes/fake_queue.go
@@ -0,0 +1,122 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package tasklistfakes
+
+import (
+	"context"
+	"sync"
+
+	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist"
+)
+
+type FakeQueue struct {
+	AddTaskListStub        func(context.Context, *tasklist.TaskList, []*task.Task) error
+	addTaskListMutex       sync.RWMutex
+	addTaskListArgsForCall []struct {
+		arg1 context.Context
+		arg2 *tasklist.TaskList
+		arg3 []*task.Task
+	}
+	addTaskListReturns struct {
+		result1 error
+	}
+	addTaskListReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *FakeQueue) AddTaskList(arg1 context.Context, arg2 *tasklist.TaskList, arg3 []*task.Task) error {
+	var arg3Copy []*task.Task
+	if arg3 != nil {
+		arg3Copy = make([]*task.Task, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.addTaskListMutex.Lock()
+	ret, specificReturn := fake.addTaskListReturnsOnCall[len(fake.addTaskListArgsForCall)]
+	fake.addTaskListArgsForCall = append(fake.addTaskListArgsForCall, struct {
+		arg1 context.Context
+		arg2 *tasklist.TaskList
+		arg3 []*task.Task
+	}{arg1, arg2, arg3Copy})
+	stub := fake.AddTaskListStub
+	fakeReturns := fake.addTaskListReturns
+	fake.recordInvocation("AddTaskList", []interface{}{arg1, arg2, arg3Copy})
+	fake.addTaskListMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *FakeQueue) AddTaskListCallCount() int {
+	fake.addTaskListMutex.RLock()
+	defer fake.addTaskListMutex.RUnlock()
+	return len(fake.addTaskListArgsForCall)
+}
+
+func (fake *FakeQueue) AddTaskListCalls(stub func(context.Context, *tasklist.TaskList, []*task.Task) error) {
+	fake.addTaskListMutex.Lock()
+	defer fake.addTaskListMutex.Unlock()
+	fake.AddTaskListStub = stub
+}
+
+func (fake *FakeQueue) AddTaskListArgsForCall(i int) (context.Context, *tasklist.TaskList, []*task.Task) {
+	fake.addTaskListMutex.RLock()
+	defer fake.addTaskListMutex.RUnlock()
+	argsForCall := fake.addTaskListArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *FakeQueue) AddTaskListReturns(result1 error) {
+	fake.addTaskListMutex.Lock()
+	defer fake.addTaskListMutex.Unlock()
+	fake.AddTaskListStub = nil
+	fake.addTaskListReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FakeQueue) AddTaskListReturnsOnCall(i int, result1 error) {
+	fake.addTaskListMutex.Lock()
+	defer fake.addTaskListMutex.Unlock()
+	fake.AddTaskListStub = nil
+	if fake.addTaskListReturnsOnCall == nil {
+		fake.addTaskListReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.addTaskListReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FakeQueue) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.addTaskListMutex.RLock()
+	defer fake.addTaskListMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *FakeQueue) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ tasklist.Queue = new(FakeQueue)
diff --git a/internal/service/tasklist/tasklistfakes/fake_storage.go b/internal/service/tasklist/tasklistfakes/fake_storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..9ece29b9180862d8281bd5759b4104ff9a731e67
--- /dev/null
+++ b/internal/service/tasklist/tasklistfakes/fake_storage.go
@@ -0,0 +1,206 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package tasklistfakes
+
+import (
+	"context"
+	"sync"
+
+	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist"
+)
+
+type FakeStorage struct {
+	TaskListTemplateStub        func(context.Context, string) (*tasklist.Template, error)
+	taskListTemplateMutex       sync.RWMutex
+	taskListTemplateArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+	}
+	taskListTemplateReturns struct {
+		result1 *tasklist.Template
+		result2 error
+	}
+	taskListTemplateReturnsOnCall map[int]struct {
+		result1 *tasklist.Template
+		result2 error
+	}
+	TaskTemplatesStub        func(context.Context, []string) (map[string]*task.Task, error)
+	taskTemplatesMutex       sync.RWMutex
+	taskTemplatesArgsForCall []struct {
+		arg1 context.Context
+		arg2 []string
+	}
+	taskTemplatesReturns struct {
+		result1 map[string]*task.Task
+		result2 error
+	}
+	taskTemplatesReturnsOnCall map[int]struct {
+		result1 map[string]*task.Task
+		result2 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *FakeStorage) TaskListTemplate(arg1 context.Context, arg2 string) (*tasklist.Template, error) {
+	fake.taskListTemplateMutex.Lock()
+	ret, specificReturn := fake.taskListTemplateReturnsOnCall[len(fake.taskListTemplateArgsForCall)]
+	fake.taskListTemplateArgsForCall = append(fake.taskListTemplateArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.TaskListTemplateStub
+	fakeReturns := fake.taskListTemplateReturns
+	fake.recordInvocation("TaskListTemplate", []interface{}{arg1, arg2})
+	fake.taskListTemplateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *FakeStorage) TaskListTemplateCallCount() int {
+	fake.taskListTemplateMutex.RLock()
+	defer fake.taskListTemplateMutex.RUnlock()
+	return len(fake.taskListTemplateArgsForCall)
+}
+
+func (fake *FakeStorage) TaskListTemplateCalls(stub func(context.Context, string) (*tasklist.Template, error)) {
+	fake.taskListTemplateMutex.Lock()
+	defer fake.taskListTemplateMutex.Unlock()
+	fake.TaskListTemplateStub = stub
+}
+
+func (fake *FakeStorage) TaskListTemplateArgsForCall(i int) (context.Context, string) {
+	fake.taskListTemplateMutex.RLock()
+	defer fake.taskListTemplateMutex.RUnlock()
+	argsForCall := fake.taskListTemplateArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *FakeStorage) TaskListTemplateReturns(result1 *tasklist.Template, result2 error) {
+	fake.taskListTemplateMutex.Lock()
+	defer fake.taskListTemplateMutex.Unlock()
+	fake.TaskListTemplateStub = nil
+	fake.taskListTemplateReturns = struct {
+		result1 *tasklist.Template
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) TaskListTemplateReturnsOnCall(i int, result1 *tasklist.Template, result2 error) {
+	fake.taskListTemplateMutex.Lock()
+	defer fake.taskListTemplateMutex.Unlock()
+	fake.TaskListTemplateStub = nil
+	if fake.taskListTemplateReturnsOnCall == nil {
+		fake.taskListTemplateReturnsOnCall = make(map[int]struct {
+			result1 *tasklist.Template
+			result2 error
+		})
+	}
+	fake.taskListTemplateReturnsOnCall[i] = struct {
+		result1 *tasklist.Template
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) TaskTemplates(arg1 context.Context, arg2 []string) (map[string]*task.Task, error) {
+	var arg2Copy []string
+	if arg2 != nil {
+		arg2Copy = make([]string, len(arg2))
+		copy(arg2Copy, arg2)
+	}
+	fake.taskTemplatesMutex.Lock()
+	ret, specificReturn := fake.taskTemplatesReturnsOnCall[len(fake.taskTemplatesArgsForCall)]
+	fake.taskTemplatesArgsForCall = append(fake.taskTemplatesArgsForCall, struct {
+		arg1 context.Context
+		arg2 []string
+	}{arg1, arg2Copy})
+	stub := fake.TaskTemplatesStub
+	fakeReturns := fake.taskTemplatesReturns
+	fake.recordInvocation("TaskTemplates", []interface{}{arg1, arg2Copy})
+	fake.taskTemplatesMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *FakeStorage) TaskTemplatesCallCount() int {
+	fake.taskTemplatesMutex.RLock()
+	defer fake.taskTemplatesMutex.RUnlock()
+	return len(fake.taskTemplatesArgsForCall)
+}
+
+func (fake *FakeStorage) TaskTemplatesCalls(stub func(context.Context, []string) (map[string]*task.Task, error)) {
+	fake.taskTemplatesMutex.Lock()
+	defer fake.taskTemplatesMutex.Unlock()
+	fake.TaskTemplatesStub = stub
+}
+
+func (fake *FakeStorage) TaskTemplatesArgsForCall(i int) (context.Context, []string) {
+	fake.taskTemplatesMutex.RLock()
+	defer fake.taskTemplatesMutex.RUnlock()
+	argsForCall := fake.taskTemplatesArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *FakeStorage) TaskTemplatesReturns(result1 map[string]*task.Task, result2 error) {
+	fake.taskTemplatesMutex.Lock()
+	defer fake.taskTemplatesMutex.Unlock()
+	fake.TaskTemplatesStub = nil
+	fake.taskTemplatesReturns = struct {
+		result1 map[string]*task.Task
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) TaskTemplatesReturnsOnCall(i int, result1 map[string]*task.Task, result2 error) {
+	fake.taskTemplatesMutex.Lock()
+	defer fake.taskTemplatesMutex.Unlock()
+	fake.TaskTemplatesStub = nil
+	if fake.taskTemplatesReturnsOnCall == nil {
+		fake.taskTemplatesReturnsOnCall = make(map[int]struct {
+			result1 map[string]*task.Task
+			result2 error
+		})
+	}
+	fake.taskTemplatesReturnsOnCall[i] = struct {
+		result1 map[string]*task.Task
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.taskListTemplateMutex.RLock()
+	defer fake.taskListTemplateMutex.RUnlock()
+	fake.taskTemplatesMutex.RLock()
+	defer fake.taskTemplatesMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *FakeStorage) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ tasklist.Storage = new(FakeStorage)
diff --git a/internal/storage/storage.go b/internal/storage/storage.go
index f5b44125ce771b4bec90965e4637bd8e115906b9..fb0f66acf9271f3a950f347017421a4038dde3e8 100644
--- a/internal/storage/storage.go
+++ b/internal/storage/storage.go
@@ -11,31 +11,40 @@ import (
 
 	"code.vereign.com/gaiax/tsa/golib/errors"
 	"code.vereign.com/gaiax/tsa/task/internal/service/task"
+	"code.vereign.com/gaiax/tsa/task/internal/service/tasklist"
 )
 
 const (
-	taskDB        = "task"
-	taskTemplates = "taskTemplates"
-	taskQueue     = "tasks"
-	tasksHistory  = "tasksHistory"
+	taskDB            = "task"
+	taskTemplates     = "taskTemplates"
+	taskQueue         = "tasks"
+	tasksHistory      = "tasksHistory"
+	taskListQueue     = "taskLists"
+	taskListTemplates = "taskListTemplates"
+	taskListHistory   = "taskListsHistory"
 )
 
 type Storage struct {
-	templates    *mongo.Collection
-	tasks        *mongo.Collection
-	tasksHistory *mongo.Collection
+	taskTemplates     *mongo.Collection
+	tasks             *mongo.Collection
+	tasksHistory      *mongo.Collection
+	taskLists         *mongo.Collection
+	taskListTemplates *mongo.Collection
+	taskListsHistory  *mongo.Collection
 }
 
 func New(db *mongo.Client) *Storage {
 	return &Storage{
-		templates:    db.Database(taskDB).Collection(taskTemplates),
-		tasks:        db.Database(taskDB).Collection(taskQueue),
-		tasksHistory: db.Database(taskDB).Collection(tasksHistory),
+		taskTemplates:     db.Database(taskDB).Collection(taskTemplates),
+		tasks:             db.Database(taskDB).Collection(taskQueue),
+		tasksHistory:      db.Database(taskDB).Collection(tasksHistory),
+		taskListTemplates: db.Database(taskDB).Collection(taskListTemplates),
+		taskLists:         db.Database(taskDB).Collection(taskListQueue),
 	}
 }
 
 func (s *Storage) TaskTemplate(ctx context.Context, taskName string) (*task.Task, error) {
-	result := s.templates.FindOne(ctx, bson.M{
+	result := s.taskTemplates.FindOne(ctx, bson.M{
 		"name": taskName,
 	})
 
@@ -59,8 +68,8 @@ func (s *Storage) Add(ctx context.Context, task *task.Task) error {
 	return err
 }
 
-// Poll retrieves one task from the tasks collection with the
-// older ones being retrieved first (FIFO). It updates the state
+// Poll retrieves one task with empty groupID from the tasks collection
+// with the older ones being retrieved first (FIFO). It updates the state
 // of the task to "pending", so that consequent calls to Poll would
 // not retrieve the same task.
 func (s *Storage) Poll(ctx context.Context) (*task.Task, error) {
@@ -69,7 +78,7 @@ func (s *Storage) Poll(ctx context.Context) (*task.Task, error) {
 		SetSort(bson.M{"createdAt": 1}).
 		SetReturnDocument(options.After)
 
-	filter := bson.M{"state": task.Created}
+	filter := bson.M{"state": task.Created, "groupid": ""}
 	update := bson.M{"$set": bson.M{"state": task.Pending}}
 	result := s.tasks.FindOneAndUpdate(
 		ctx,
@@ -158,3 +167,76 @@ func (s *Storage) TaskHistory(ctx context.Context, taskID string) (*task.Task, e
 
 	return &task, nil
 }
+
+// TaskListTemplate retrieves one taskList definition by name from storage
+func (s *Storage) TaskListTemplate(ctx context.Context, taskListName string) (*tasklist.Template, error) {
+	result := s.taskListTemplates.FindOne(ctx, bson.M{
+		"name": taskListName,
+	})
+
+	if result.Err() != nil {
+		if strings.Contains(result.Err().Error(), "no documents in result") {
+			return nil, errors.New(errors.NotFound, "taskList template not found")
+		}
+		return nil, result.Err()
+	}
+
+	var tasklist tasklist.Template
+	if err := result.Decode(&tasklist); err != nil {
+		return nil, err
+	}
+
+	return &tasklist, nil
+}
+
+// TaskTemplates retrieves task definitions from storage by names.
+//
+// The result is a map where 'key' is the task name and 'value' is the task definition
+func (s *Storage) TaskTemplates(ctx context.Context, names []string) (map[string]*task.Task, error) {
+	cursor, err := s.taskTemplates.Find(ctx, bson.M{
+		"name": bson.M{"$in": names},
+	})
+	if err != nil {
+		return nil, err
+	}
+	defer cursor.Close(ctx)
+
+	res := make(map[string]*task.Task)
+	for cursor.Next(ctx) {
+		var task task.Task
+		if err := cursor.Decode(&task); err != nil {
+			return nil, err
+		}
+		res[task.Name] = &task
+	}
+
+	return res, nil
+}
+
+func (s *Storage) AddTaskList(ctx context.Context, taskList *tasklist.TaskList, tasks []*task.Task) error {
+	_, err := s.taskLists.InsertOne(ctx, taskList)
+	if err != nil {
+		return err
+	}
+
+	var ti []interface{}
+	for _, task := range tasks {
+		ti = append(ti, task)
+	}
+
+	_, err = s.tasks.InsertMany(ctx, ti)
+	if err != nil {
+		if err := s.AckList(ctx, taskList); err != nil { // remove taskList from queue
+			return errors.New("failed to ack taskList", err)
+		}
+		return err
+	}
+
+	return nil
+}
+
+// AckList removes a taskList from the `tasksLists` collection.
+func (s *Storage) AckList(ctx context.Context, taskList *tasklist.TaskList) error {
+	_, err := s.taskLists.DeleteOne(ctx, bson.M{"id": taskList.ID})
+	return err
+}