diff --git a/.env b/.env
index 43bf5fd412feeda40517d5f5e722333b92271442..568639cff029d91346e8d347f2f5cbab64407d2e 100644
--- a/.env
+++ b/.env
@@ -4,6 +4,4 @@ PORT=8080
 LOGTAIL_TOKEN=
 HTTP_TIMEOUT_SEC=2
 LOG_FLUSH_INTERVAL_MS=1000
-SMTP_USERNAME="noreply@ocw.id"
-SMTP_PORT=1025
 FE_BASE_URL="http://localhost:3000"
diff --git a/.gitignore b/.gitignore
index d3eeb070587bb63e0a455b491181f8fc408c8df1..c18416209344fed18ffcb6096897cbbef2ff3dd8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,4 @@ bin/
 tmp/
 wire_gen.go
 __debug_bin*
-.env.local
+.env.local*
diff --git a/.scannerwork/.sonar_lock b/.scannerwork/.sonar_lock
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5254c69f7309289db73b05aa53239cf41b055c97
--- /dev/null
+++ b/.scannerwork/report-task.txt
@@ -0,0 +1,6 @@
+projectKey=ocw-backend
+serverUrl=http://localhost:9000
+serverVersion=10.0.0.68432
+dashboardUrl=http://localhost:9000/dashboard?id=ocw-backend
+ceTaskId=AYeyCUSQt5Mtvce1YZdB
+ceTaskUrl=http://localhost:9000/api/ce/task?id=AYeyCUSQt5Mtvce1YZdB
diff --git a/Dockerfile b/Dockerfile
index 7673b438cedcef2e1e5775bdc6b25c6049c8d090..fb0d84339ffdb25a43bb456c86cc1262af5ef6bd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,12 +1,13 @@
 FROM golang:1.20.0-alpine3.17 AS build
 
 RUN apk add --update make
+RUN apk add --update git
 
 COPY . /app
 WORKDIR /app
 
 RUN go get
-RUN go install github.com/swaggo/swag/cmd/swag@latest
+RUN go install github.com/swaggo/swag/cmd/swag@v1.8.10
 RUN go install github.com/google/wire/cmd/wire@latest
 
 RUN make build
@@ -17,6 +18,8 @@ RUN mkdir /app
 WORKDIR /app
 
 COPY --from=build /app/bin/server.app /app
+RUN touch /app/.env
+RUN touch /app/.env.local
 
 STOPSIGNAL SIGKILL
 ENTRYPOINT [ "/app/server.app" ]
diff --git a/Dockerfile.dev b/Dockerfile.dev
index 03526f3e75455e51850f7f1186b2d2b05f140392..6f6f47c0283f6de5b2139a540fd21e919298a0ba 100644
--- a/Dockerfile.dev
+++ b/Dockerfile.dev
@@ -1,9 +1,10 @@
 FROM cosmtrek/air
 
 RUN apt install -y make
+RUN apt install -y git
 
 RUN go install github.com/google/wire/cmd/wire@latest
-RUN go install github.com/swaggo/swag/cmd/swag@latest
+RUN go install github.com/swaggo/swag/cmd/swag@v1.8.10
 
 COPY . /app
 
diff --git a/Dockerfile.test b/Dockerfile.test
index 7b6d3bf4ffb8bbfdc1eed6dfa334889e3d2ec072..d61a7100118f3f92eccfbf3f3b7b3de8948fd4f3 100644
--- a/Dockerfile.test
+++ b/Dockerfile.test
@@ -1,12 +1,13 @@
 FROM golang:1.20.0-alpine3.17 AS build
 
 RUN apk add --update make
+RUN apk add --update git
 
 COPY . /app
 WORKDIR /app
 
 RUN go get
-RUN go install github.com/swaggo/swag/cmd/swag@latest
+RUN go install github.com/swaggo/swag/cmd/swag@v1.8.10
 RUN go install github.com/google/wire/cmd/wire@latest
 
 RUN make test-dependency
diff --git a/docker-compose.yml b/docker-compose.yml
index 3eccf485e7a93a9172dcdfca800f8bcf2b732655..5194e4f7085bd96c5ae3182c99c6a8e0cb195294 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -14,11 +14,12 @@ services:
     networks:
       - api_network
   backend:
-    build:
+    build: 
       context: .
-      dockerfile: Dockerfile.dev
+      dockerfile: Dockerfile
     volumes:
-      - .:/app
+      - .env.local:/app/.env.local
+      - .env:/app/.env
     ports:
       - 8888:8080
     env_file: .env.docker
diff --git a/docs/docs.go b/docs/docs.go
index 5f078b3178044a2b1a1f0d298616d3e039da19cb..74678c232c7ed71bfdf9f00f8a77e1fc1b14475c 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1,4 +1,5 @@
-// Code generated by swaggo/swag. DO NOT EDIT
+// Code generated by swaggo/swag. DO NOT EDIT.
+
 package docs
 
 import "github.com/swaggo/swag"
@@ -1488,52 +1489,9 @@ const docTemplate = `{
                 }
             }
         },
-        "/material/{id}": {
-            "get": {
-                "description": "Get material detail",
-                "consumes": [
-                    "application/json"
-                ],
-                "produces": [
-                    "application/json"
-                ],
-                "tags": [
-                    "content"
-                ],
-                "summary": "Get material detail",
-                "parameters": [
-                    {
-                        "type": "string",
-                        "example": "IF3270",
-                        "description": "Material id",
-                        "name": "id",
-                        "in": "path",
-                        "required": true
-                    }
-                ],
-                "responses": {
-                    "200": {
-                        "description": "OK",
-                        "schema": {
-                            "allOf": [
-                                {
-                                    "$ref": "#/definitions/web.BaseResponse"
-                                },
-                                {
-                                    "type": "object",
-                                    "properties": {
-                                        "data": {
-                                            "$ref": "#/definitions/material.Material"
-                                        }
-                                    }
-                                }
-                            ]
-                        }
-                    }
-                }
-            },
-            "post": {
-                "description": "Add content of material",
+        "/lesson": {
+            "put": {
+                "description": "Add a new lesson with the given details",
                 "consumes": [
                     "application/json"
                 ],
@@ -1541,52 +1499,32 @@ const docTemplate = `{
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "lesson"
                 ],
-                "summary": "Add Content",
+                "summary": "Add a new lesson",
                 "parameters": [
                     {
                         "type": "string",
-                        "description": "Access token",
+                        "description": "AddLessonToken",
                         "name": "Authorization",
                         "in": "header",
                         "required": true
                     },
                     {
-                        "description": "Add content request",
+                        "description": "Add Lesson payload",
                         "name": "data",
                         "in": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/material.NewContentRequest"
+                            "$ref": "#/definitions/lesson.AddLessonRequestPayload"
                         }
-                    },
-                    {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Material id",
-                        "name": "id",
-                        "in": "path",
-                        "required": true
                     }
                 ],
                 "responses": {
                     "200": {
-                        "description": "OK",
+                        "description": "Success",
                         "schema": {
-                            "allOf": [
-                                {
-                                    "$ref": "#/definitions/web.BaseResponse"
-                                },
-                                {
-                                    "type": "object",
-                                    "properties": {
-                                        "data": {
-                                            "$ref": "#/definitions/material.NewContentResponse"
-                                        }
-                                    }
-                                }
-                            ]
+                            "$ref": "#/definitions/web.BaseResponse"
                         }
                     },
                     "400": {
@@ -1600,33 +1538,42 @@ const docTemplate = `{
                         "schema": {
                             "$ref": "#/definitions/web.BaseResponse"
                         }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
                     }
                 }
-            },
-            "delete": {
-                "description": "Delete material",
-                "consumes": [
-                    "application/json"
-                ],
+            }
+        },
+        "/lesson/course/{id}": {
+            "get": {
+                "description": "Retrieve lesson data by course ID",
                 "produces": [
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "lesson"
                 ],
-                "summary": "Delete material",
+                "summary": "Get lesson by course ID",
                 "parameters": [
                     {
                         "type": "string",
-                        "description": "Access token",
-                        "name": "Authorization",
-                        "in": "header",
-                        "required": true
-                    },
-                    {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Material id",
+                        "description": "Course ID",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1634,7 +1581,25 @@ const docTemplate = `{
                 ],
                 "responses": {
                     "200": {
-                        "description": "OK",
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid ID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
                         "schema": {
                             "$ref": "#/definitions/web.BaseResponse"
                         }
@@ -1642,9 +1607,9 @@ const docTemplate = `{
                 }
             }
         },
-        "/material/{id}/content/{content-id}": {
-            "delete": {
-                "description": "Delete content of material",
+        "/lesson/material": {
+            "put": {
+                "description": "Add a new lesson material with the given details",
                 "consumes": [
                     "application/json"
                 ],
@@ -1652,37 +1617,60 @@ const docTemplate = `{
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "lesson"
                 ],
-                "summary": "Delete Content",
+                "summary": "Add a new lesson material",
                 "parameters": [
                     {
                         "type": "string",
-                        "description": "Access token",
+                        "description": "AddLessonMaterialsToken",
                         "name": "Authorization",
                         "in": "header",
                         "required": true
                     },
                     {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Material id",
-                        "name": "id",
-                        "in": "path",
-                        "required": true
-                    },
-                    {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Content id",
-                        "name": "content-id",
-                        "in": "path",
-                        "required": true
+                        "description": "Add Lesson Material payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/materials.AddLessonMaterialsRequestPayload"
+                        }
                     }
                 ],
                 "responses": {
                     "200": {
-                        "description": "OK",
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
                         "schema": {
                             "$ref": "#/definitions/web.BaseResponse"
                         }
@@ -1690,24 +1678,20 @@ const docTemplate = `{
                 }
             }
         },
-        "/quiz": {
-            "put": {
-                "description": "New Quiz",
-                "consumes": [
-                    "application/json"
-                ],
+        "/lesson/material/lesson/{id}": {
+            "get": {
+                "description": "Retrieve lesson materials data by lesson ID",
                 "produces": [
                     "application/json"
                 ],
                 "tags": [
-                    "quiz"
+                    "lesson"
                 ],
-                "summary": "New Quiz",
+                "summary": "Get lesson materials by lesson ID",
                 "parameters": [
                     {
                         "type": "string",
-                        "format": "uuid",
-                        "description": "Quiz id",
+                        "description": "Lesson ID (UUID)",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1715,7 +1699,25 @@ const docTemplate = `{
                 ],
                 "responses": {
                     "200": {
-                        "description": "OK",
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
                         "schema": {
                             "$ref": "#/definitions/web.BaseResponse"
                         }
@@ -1723,24 +1725,20 @@ const docTemplate = `{
                 }
             }
         },
-        "/quiz/{id}": {
+        "/lesson/material/{id}": {
             "get": {
-                "description": "Get Quiz Detail",
-                "consumes": [
-                    "application/json"
-                ],
+                "description": "Retrieve lesson data by UUID",
                 "produces": [
                     "application/json"
                 ],
                 "tags": [
-                    "quiz"
+                    "lesson"
                 ],
-                "summary": "Get Quiz Detail",
+                "summary": "Get lesson by ID",
                 "parameters": [
                     {
                         "type": "string",
-                        "format": "uuid",
-                        "description": "Quiz id",
+                        "description": "Lesson ID (UUID)",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1748,29 +1746,566 @@ const docTemplate = `{
                 ],
                 "responses": {
                     "200": {
-                        "description": "OK",
+                        "description": "Success",
                         "schema": {
-                            "allOf": [
-                                {
-                                    "$ref": "#/definitions/web.BaseResponse"
-                                },
-                                {
-                                    "type": "object",
-                                    "properties": {
-                                        "data": {
-                                            "$ref": "#/definitions/quiz.Quiz"
-                                        }
-                                    }
-                                }
-                            ]
+                            "$ref": "#/definitions/web.BaseResponse"
                         }
-                    }
-                }
-            },
-            "delete": {
-                "description": "Delete Quiz",
-                "consumes": [
-                    "application/json"
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete a lesson material with the specified ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Delete lesson material by id",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson Material ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "DeleteLessonMaterialToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/{id}": {
+            "get": {
+                "description": "Retrieve lesson data by UUID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Get lesson by ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete a lesson with the specified ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Delete lesson by ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "DeleteLessonToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "patch": {
+                "description": "Update a lesson material with the given ID",
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Update a lesson material",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson Material ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Update Lesson Materials Payload",
+                        "name": "payload",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/materials.UpdateLessonMaterialsRequestPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "UpdateLessonMaterialsToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/material/{id}": {
+            "get": {
+                "description": "Get material detail",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "content"
+                ],
+                "summary": "Get material detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "example": "IF3270",
+                        "description": "Material id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/material.Material"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "post": {
+                "description": "Add content of material",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "content"
+                ],
+                "summary": "Add Content",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Access token",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Add content request",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/material.NewContentRequest"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Material id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/material.NewContentResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete material",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "content"
+                ],
+                "summary": "Delete material",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Access token",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Material id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/material/{id}/content/{content-id}": {
+            "delete": {
+                "description": "Delete content of material",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "content"
+                ],
+                "summary": "Delete Content",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Access token",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Material id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Content id",
+                        "name": "content-id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz": {
+            "put": {
+                "description": "New Quiz",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "New Quiz",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz/{id}": {
+            "get": {
+                "description": "Get Quiz Detail",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Get Quiz Detail",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.Quiz"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete Quiz",
+                "consumes": [
+                    "application/json"
                 ],
                 "produces": [
                     "application/json"
@@ -1799,6 +2334,67 @@ const docTemplate = `{
                 }
             }
         },
+        "/quiz/{id}/finish": {
+            "post": {
+                "description": "Finish quiz session and get the score",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Finish Quiz",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Quiz Finish payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.FinishQuizPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/quiz/{id}/solution": {
             "get": {
                 "description": "Take a quiz",
@@ -1853,7 +2449,7 @@ const docTemplate = `{
         },
         "/quiz/{id}/take": {
             "post": {
-                "description": "Finish quiz session and get the score",
+                "description": "Take a quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1863,7 +2459,7 @@ const docTemplate = `{
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Finish Quiz",
+                "summary": "Take Quiz",
                 "parameters": [
                     {
                         "type": "string",
@@ -1872,15 +2468,6 @@ const docTemplate = `{
                         "in": "header",
                         "required": true
                     },
-                    {
-                        "description": "Quiz Finish payload",
-                        "name": "data",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "$ref": "#/definitions/quiz.FinishQuizPayload"
-                        }
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
@@ -2153,10 +2740,6 @@ const docTemplate = `{
                     "type": "string",
                     "example": "someone@example.com"
                 },
-                "id": {
-                    "description": "Course ID, Provided by query",
-                    "type": "string"
-                },
                 "lecturer": {
                     "description": "Course Lecturer",
                     "type": "string"
@@ -2213,10 +2796,6 @@ const docTemplate = `{
                     "description": "Faculty Name Abbreviation",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Faculty ID, Provided by Query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Faculty Name",
                     "type": "string"
@@ -2227,6 +2806,68 @@ const docTemplate = `{
                 }
             }
         },
+        "lesson.AddLessonRequestPayload": {
+            "description": "Information that should be available when you add a lesson",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name",
+                "order"
+            ],
+            "properties": {
+                "addLessonToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "description": {
+                    "description": "Lesson Description (Can be left empty)",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Lesson Name",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Order",
+                    "type": "integer"
+                }
+            }
+        },
+        "lesson.UpdateLessonRequestPayload": {
+            "description": "Information that should be available when you update a lesson",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name",
+                "order"
+            ],
+            "properties": {
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "description": {
+                    "description": "Lesson Description (Can be left empty)",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Lesson Name",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Order",
+                    "type": "integer"
+                },
+                "updateLessonToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "login.LoginRequestPayload": {
             "description": "Information that should be available when do a login process",
             "type": "object",
@@ -2311,10 +2952,6 @@ const docTemplate = `{
                     "description": "Faculty Id, will be set by the server",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Major ID, provided by query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Major Name",
                     "type": "string"
@@ -2422,6 +3059,68 @@ const docTemplate = `{
                 }
             }
         },
+        "materials.AddLessonMaterialsRequestPayload": {
+            "description": "Information that should be available when you add a lesson material",
+            "type": "object",
+            "required": [
+                "contents",
+                "lesson_id",
+                "order"
+            ],
+            "properties": {
+                "addLessonMaterialsToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "contents": {
+                    "description": "Lesson Contents",
+                    "type": "string"
+                },
+                "lesson_id": {
+                    "description": "Lesson ID",
+                    "type": "string"
+                },
+                "material_id": {
+                    "description": "Lesson Material ID, optional",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Material Order",
+                    "type": "integer"
+                }
+            }
+        },
+        "materials.UpdateLessonMaterialsRequestPayload": {
+            "description": "Information that should be available when you update a lesson material",
+            "type": "object",
+            "required": [
+                "contents",
+                "lesson_id",
+                "order"
+            ],
+            "properties": {
+                "contents": {
+                    "description": "Lesson Contents",
+                    "type": "string"
+                },
+                "lesson_id": {
+                    "description": "Lesson ID",
+                    "type": "string"
+                },
+                "material_id": {
+                    "description": "Lesson Material ID, optional",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Material Order",
+                    "type": "integer"
+                },
+                "updateLessonMaterialsToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "quiz.AnswerOption": {
             "type": "object",
             "properties": {
diff --git a/docs/swagger.json b/docs/swagger.json
index f17f85a584a768be7ca566f26941c0552cc89aaa..7d7802bc413765ed1066d2f8d08270a03e5b116a 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -1480,6 +1480,540 @@
                 }
             }
         },
+        "/lesson": {
+            "put": {
+                "description": "Add a new lesson with the given details",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Add a new lesson",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "AddLessonToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Add Lesson payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/lesson.AddLessonRequestPayload"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/course/{id}": {
+            "get": {
+                "description": "Retrieve lesson data by course ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Get lesson by course ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Course ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid ID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/material": {
+            "put": {
+                "description": "Add a new lesson material with the given details",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Add a new lesson material",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "AddLessonMaterialsToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Add Lesson Material payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/materials.AddLessonMaterialsRequestPayload"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/material/lesson/{id}": {
+            "get": {
+                "description": "Retrieve lesson materials data by lesson ID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Get lesson materials by lesson ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/material/{id}": {
+            "get": {
+                "description": "Retrieve lesson data by UUID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Get lesson by ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete a lesson material with the specified ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Delete lesson material by id",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson Material ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "DeleteLessonMaterialToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/lesson/{id}": {
+            "get": {
+                "description": "Retrieve lesson data by UUID",
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Get lesson by ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Invalid UUID provided in request path",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "delete": {
+                "description": "Delete a lesson with the specified ID",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Delete lesson by ID",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson ID",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "description": "DeleteLessonToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            },
+            "patch": {
+                "description": "Update a lesson material with the given ID",
+                "tags": [
+                    "lesson"
+                ],
+                "summary": "Update a lesson material",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Lesson Material ID (UUID)",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "Update Lesson Materials Payload",
+                        "name": "payload",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/materials.UpdateLessonMaterialsRequestPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "UpdateLessonMaterialsToken",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Success",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "400": {
+                        "description": "Bad Request",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "401": {
+                        "description": "Unauthorized",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "403": {
+                        "description": "Forbidden",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "422": {
+                        "description": "Unprocessable Entity",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
         "/material/{id}": {
             "get": {
                 "description": "Get material detail",
@@ -1791,6 +2325,67 @@
                 }
             }
         },
+        "/quiz/{id}/finish": {
+            "post": {
+                "description": "Finish quiz session and get the score",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Finish Quiz",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Quiz Finish payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.FinishQuizPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/quiz/{id}/solution": {
             "get": {
                 "description": "Take a quiz",
@@ -1845,7 +2440,7 @@
         },
         "/quiz/{id}/take": {
             "post": {
-                "description": "Finish quiz session and get the score",
+                "description": "Take a quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1855,7 +2450,7 @@
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Finish Quiz",
+                "summary": "Take Quiz",
                 "parameters": [
                     {
                         "type": "string",
@@ -1864,15 +2459,6 @@
                         "in": "header",
                         "required": true
                     },
-                    {
-                        "description": "Quiz Finish payload",
-                        "name": "data",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "$ref": "#/definitions/quiz.FinishQuizPayload"
-                        }
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
@@ -2145,10 +2731,6 @@
                     "type": "string",
                     "example": "someone@example.com"
                 },
-                "id": {
-                    "description": "Course ID, Provided by query",
-                    "type": "string"
-                },
                 "lecturer": {
                     "description": "Course Lecturer",
                     "type": "string"
@@ -2205,10 +2787,6 @@
                     "description": "Faculty Name Abbreviation",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Faculty ID, Provided by Query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Faculty Name",
                     "type": "string"
@@ -2219,6 +2797,68 @@
                 }
             }
         },
+        "lesson.AddLessonRequestPayload": {
+            "description": "Information that should be available when you add a lesson",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name",
+                "order"
+            ],
+            "properties": {
+                "addLessonToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "description": {
+                    "description": "Lesson Description (Can be left empty)",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Lesson Name",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Order",
+                    "type": "integer"
+                }
+            }
+        },
+        "lesson.UpdateLessonRequestPayload": {
+            "description": "Information that should be available when you update a lesson",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name",
+                "order"
+            ],
+            "properties": {
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "description": {
+                    "description": "Lesson Description (Can be left empty)",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Lesson Name",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Order",
+                    "type": "integer"
+                },
+                "updateLessonToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "login.LoginRequestPayload": {
             "description": "Information that should be available when do a login process",
             "type": "object",
@@ -2303,10 +2943,6 @@
                     "description": "Faculty Id, will be set by the server",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Major ID, provided by query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Major Name",
                     "type": "string"
@@ -2414,6 +3050,68 @@
                 }
             }
         },
+        "materials.AddLessonMaterialsRequestPayload": {
+            "description": "Information that should be available when you add a lesson material",
+            "type": "object",
+            "required": [
+                "contents",
+                "lesson_id",
+                "order"
+            ],
+            "properties": {
+                "addLessonMaterialsToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "contents": {
+                    "description": "Lesson Contents",
+                    "type": "string"
+                },
+                "lesson_id": {
+                    "description": "Lesson ID",
+                    "type": "string"
+                },
+                "material_id": {
+                    "description": "Lesson Material ID, optional",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Material Order",
+                    "type": "integer"
+                }
+            }
+        },
+        "materials.UpdateLessonMaterialsRequestPayload": {
+            "description": "Information that should be available when you update a lesson material",
+            "type": "object",
+            "required": [
+                "contents",
+                "lesson_id",
+                "order"
+            ],
+            "properties": {
+                "contents": {
+                    "description": "Lesson Contents",
+                    "type": "string"
+                },
+                "lesson_id": {
+                    "description": "Lesson ID",
+                    "type": "string"
+                },
+                "material_id": {
+                    "description": "Lesson Material ID, optional",
+                    "type": "string"
+                },
+                "order": {
+                    "description": "Lesson Material Order",
+                    "type": "integer"
+                },
+                "updateLessonMaterialsToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "quiz.AnswerOption": {
             "type": "object",
             "properties": {
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 30750e1a5c2197a440b395eeb782798eda0799fd..b39336da946758345aadf855e855615703b341ab 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -102,9 +102,6 @@ definitions:
         description: Contributor Email
         example: someone@example.com
         type: string
-      id:
-        description: Course ID, Provided by query
-        type: string
       lecturer:
         description: Course Lecturer
         type: string
@@ -148,9 +145,6 @@ definitions:
       abbreviation:
         description: Faculty Name Abbreviation
         type: string
-      id:
-        description: Faculty ID, Provided by Query
-        type: string
       name:
         description: Faculty Name
         type: string
@@ -161,6 +155,52 @@ definitions:
     - abbreviation
     - name
     type: object
+  lesson.AddLessonRequestPayload:
+    description: Information that should be available when you add a lesson
+    properties:
+      addLessonToken:
+        description: Web Token that was appended to the link
+        type: string
+      course_id:
+        description: Course ID
+        type: string
+      description:
+        description: Lesson Description (Can be left empty)
+        type: string
+      name:
+        description: Lesson Name
+        type: string
+      order:
+        description: Lesson Order
+        type: integer
+    required:
+    - course_id
+    - name
+    - order
+    type: object
+  lesson.UpdateLessonRequestPayload:
+    description: Information that should be available when you update a lesson
+    properties:
+      course_id:
+        description: Course ID
+        type: string
+      description:
+        description: Lesson Description (Can be left empty)
+        type: string
+      name:
+        description: Lesson Name
+        type: string
+      order:
+        description: Lesson Order
+        type: integer
+      updateLessonToken:
+        description: Web Token that was appended to the link
+        type: string
+    required:
+    - course_id
+    - name
+    - order
+    type: object
   login.LoginRequestPayload:
     description: Information that should be available when do a login process
     properties:
@@ -220,9 +260,6 @@ definitions:
       faculty_id:
         description: Faculty Id, will be set by the server
         type: string
-      id:
-        description: Major ID, provided by query
-        type: string
       name:
         description: Major Name
         type: string
@@ -297,6 +334,52 @@ definitions:
       upload_link:
         type: string
     type: object
+  materials.AddLessonMaterialsRequestPayload:
+    description: Information that should be available when you add a lesson material
+    properties:
+      addLessonMaterialsToken:
+        description: Web Token that was appended to the link
+        type: string
+      contents:
+        description: Lesson Contents
+        type: string
+      lesson_id:
+        description: Lesson ID
+        type: string
+      material_id:
+        description: Lesson Material ID, optional
+        type: string
+      order:
+        description: Lesson Material Order
+        type: integer
+    required:
+    - contents
+    - lesson_id
+    - order
+    type: object
+  materials.UpdateLessonMaterialsRequestPayload:
+    description: Information that should be available when you update a lesson material
+    properties:
+      contents:
+        description: Lesson Contents
+        type: string
+      lesson_id:
+        description: Lesson ID
+        type: string
+      material_id:
+        description: Lesson Material ID, optional
+        type: string
+      order:
+        description: Lesson Material Order
+        type: integer
+      updateLessonMaterialsToken:
+        description: Web Token that was appended to the link
+        type: string
+    required:
+    - contents
+    - lesson_id
+    - order
+    type: object
   quiz.AnswerOption:
     properties:
       answer:
@@ -1416,6 +1499,361 @@ paths:
       summary: Get courses by major
       tags:
       - course
+  /lesson:
+    put:
+      consumes:
+      - application/json
+      description: Add a new lesson with the given details
+      parameters:
+      - description: AddLessonToken
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: Add Lesson payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/lesson.AddLessonRequestPayload'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "422":
+          description: Unprocessable Entity
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Add a new lesson
+      tags:
+      - lesson
+  /lesson/{id}:
+    delete:
+      consumes:
+      - application/json
+      description: Delete a lesson with the specified ID
+      parameters:
+      - description: Lesson ID
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: DeleteLessonToken
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "422":
+          description: Unprocessable Entity
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Delete lesson by ID
+      tags:
+      - lesson
+    get:
+      description: Retrieve lesson data by UUID
+      parameters:
+      - description: Lesson ID (UUID)
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Invalid UUID provided in request path
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Get lesson by ID
+      tags:
+      - lesson
+    patch:
+      description: Update a lesson material with the given ID
+      parameters:
+      - description: Lesson Material ID (UUID)
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: Update Lesson Materials Payload
+        in: body
+        name: payload
+        required: true
+        schema:
+          $ref: '#/definitions/materials.UpdateLessonMaterialsRequestPayload'
+      - description: UpdateLessonMaterialsToken
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "422":
+          description: Unprocessable Entity
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Update a lesson material
+      tags:
+      - lesson
+  /lesson/course/{id}:
+    get:
+      description: Retrieve lesson data by course ID
+      parameters:
+      - description: Course ID
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Invalid ID provided in request path
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Get lesson by course ID
+      tags:
+      - lesson
+  /lesson/material:
+    put:
+      consumes:
+      - application/json
+      description: Add a new lesson material with the given details
+      parameters:
+      - description: AddLessonMaterialsToken
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: Add Lesson Material payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/materials.AddLessonMaterialsRequestPayload'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "422":
+          description: Unprocessable Entity
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Add a new lesson material
+      tags:
+      - lesson
+  /lesson/material/{id}:
+    delete:
+      consumes:
+      - application/json
+      description: Delete a lesson material with the specified ID
+      parameters:
+      - description: Lesson Material ID
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: DeleteLessonMaterialToken
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "422":
+          description: Unprocessable Entity
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Delete lesson material by id
+      tags:
+      - lesson
+    get:
+      description: Retrieve lesson data by UUID
+      parameters:
+      - description: Lesson ID (UUID)
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Invalid UUID provided in request path
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Get lesson by ID
+      tags:
+      - lesson
+  /lesson/material/lesson/{id}:
+    get:
+      description: Retrieve lesson materials data by lesson ID
+      parameters:
+      - description: Lesson ID (UUID)
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: Success
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "400":
+          description: Invalid UUID provided in request path
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Get lesson materials by lesson ID
+      tags:
+      - lesson
   /material/{id}:
     delete:
       consumes:
@@ -1617,6 +2055,44 @@ paths:
       summary: Get Quiz Detail
       tags:
       - quiz
+  /quiz/{id}/finish:
+    post:
+      consumes:
+      - application/json
+      description: Finish quiz session and get the score
+      parameters:
+      - description: Authenticate User (any role)
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: Quiz Finish payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/quiz.FinishQuizPayload'
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/web.BaseResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/quiz.QuizDetail'
+              type: object
+      summary: Finish Quiz
+      tags:
+      - quiz
   /quiz/{id}/solution:
     get:
       consumes:
@@ -1653,19 +2129,13 @@ paths:
     post:
       consumes:
       - application/json
-      description: Finish quiz session and get the score
+      description: Take a quiz
       parameters:
       - description: Authenticate User (any role)
         in: header
         name: Authorization
         required: true
         type: string
-      - description: Quiz Finish payload
-        in: body
-        name: data
-        required: true
-        schema:
-          $ref: '#/definitions/quiz.FinishQuizPayload'
       - description: Quiz id
         format: uuid
         in: path
@@ -1684,7 +2154,7 @@ paths:
                 data:
                   $ref: '#/definitions/quiz.QuizDetail'
               type: object
-      summary: Finish Quiz
+      summary: Take Quiz
       tags:
       - quiz
   /reset/confirm:
diff --git a/handler/di.go b/handler/di.go
index 399ef81ecbb23c9d70b0431c6129610c92d5dadc..aefdce321930ee174f0b93d23d3eadc8f3988adc 100644
--- a/handler/di.go
+++ b/handler/di.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.informatika.org/ocw/ocw-backend/handler/auth"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/common"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/course"
+	"gitlab.informatika.org/ocw/ocw-backend/handler/lesson"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/material"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/reset"
@@ -37,6 +38,10 @@ var HandlerSet = wire.NewSet(
 	wire.Struct(new(course.CourseHandlerImpl), "*"),
 	wire.Bind(new(course.CourseHandler), new(*course.CourseHandlerImpl)),
 
+	// Lesson
+	wire.Struct(new(lesson.LessonHandlerImpl), "*"),
+	wire.Bind(new(lesson.LessonHandler), new(*lesson.LessonHandlerImpl)),
+	
 	// Material
 	wire.Struct(new(material.MaterialHandlerImpl), "*"),
 	wire.Bind(new(material.MaterialHandler), new(*material.MaterialHandlerImpl)),
diff --git a/handler/lesson/addLesson.go b/handler/lesson/addLesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..162892b3af78a0b9d12b1c463139004e67c589e7
--- /dev/null
+++ b/handler/lesson/addLesson.go
@@ -0,0 +1,100 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-playground/validator/v10"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+)
+
+// Index godoc
+//
+//	@Summary		Add a new lesson
+//	@Description	Add a new lesson with the given details
+//	@Tags			lesson
+//	@Accept			json
+//	@Produce		json
+//	@Param			Authorization	header		string							true	"AddLessonToken"
+//	@Param			data			body		lesson.AddLessonRequestPayload	true	"Add Lesson payload"
+//	@Success		200				{object}	web.BaseResponse				"Success"
+//	@Failure		400				{object}	web.BaseResponse				"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse				"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse				"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse				"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse				"Internal Server Error"
+//	@Router			/lesson [put]
+func (l LessonHandlerImpl) AddLesson(w http.ResponseWriter, r *http.Request) {
+	payload := lesson.AddLessonRequestPayload{}
+
+	// Validate payload
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := l.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := l.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		l.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	validate := validator.New()
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := l.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	payload.AddLessonToken = token[1]
+	err := l.LessonService.AddLesson(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/addLessonMaterial.go b/handler/lesson/addLessonMaterial.go
new file mode 100644
index 0000000000000000000000000000000000000000..bd549025b68e6fcc72e63dbfc18b0964d4dc9281
--- /dev/null
+++ b/handler/lesson/addLessonMaterial.go
@@ -0,0 +1,102 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-playground/validator/v10"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+// Index godoc
+//
+//	@Summary		Add a new lesson material
+//	@Description	Add a new lesson material with the given details
+//	@Tags			lesson
+//	@Accept			json
+//	@Produce		json
+//	@Param			Authorization	header		string							true	"AddLessonMaterialsToken"
+//	@Param			data			body		materials.AddLessonMaterialsRequestPayload	true	"Add Lesson Material payload"
+//	@Success		200				{object}	web.BaseResponse				"Success"
+//	@Failure		400				{object}	web.BaseResponse				"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse				"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse				"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse				"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse				"Internal Server Error"
+//	@Router			/lesson/material [put]
+func (l LessonHandlerImpl) AddLessonMaterial(w http.ResponseWriter, r *http.Request) {
+	payload := materials.AddLessonMaterialsRequestPayload{}
+
+	// Validate payload
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := l.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := l.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		l.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	validate := validator.New()
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := l.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+		return
+	}
+
+	payload.AddLessonMaterialsToken = token[1]
+	err := l.LessonService.AddLessonMaterial(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
diff --git a/handler/lesson/deleteLesson.go b/handler/lesson/deleteLesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..e00f057f39a8a931716c2f24cb6d3a0781ad8b3a
--- /dev/null
+++ b/handler/lesson/deleteLesson.go
@@ -0,0 +1,84 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+)
+
+// Index godoc
+//
+//	@Summary		Delete lesson by ID
+//	@Description	Delete a lesson with the specified ID
+//	@Tags			lesson
+//	@Accept			json
+//	@Produce		json
+//  @Param          id			  path        string                          true        "Lesson ID"
+//	@Param			Authorization	header		string							true	"DeleteLessonToken"
+//	@Success		200				{object}	web.BaseResponse				"Success"
+//	@Failure		400				{object}	web.BaseResponse				"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse				"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse				"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse				"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse				"Internal Server Error"
+//	@Router			/lesson/{id} [delete]
+func (l LessonHandlerImpl) DeleteLesson(w http.ResponseWriter, r *http.Request) {
+	payload := lesson.DeleteByUUIDRequestPayload{}
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.DeleteLessonToken = token[1]
+	payload.ID = id
+	err = l.LessonService.DeleteLesson(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/deleteLessonMaterial.go b/handler/lesson/deleteLessonMaterial.go
new file mode 100644
index 0000000000000000000000000000000000000000..ee814d240edca4162133a8ad6515e53b83d5d51d
--- /dev/null
+++ b/handler/lesson/deleteLessonMaterial.go
@@ -0,0 +1,85 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+// Index godoc
+//
+//	@Summary		Delete lesson material by id
+//	@Description	Delete a lesson material with the specified ID
+//  @Tags			lesson
+//	@Accept			json
+//	@Produce		json
+//  @Param          id			  path        string                          true        "Lesson Material ID"
+//	@Param			Authorization	header		string							true	"DeleteLessonMaterialToken"
+//	@Success		200				{object}	web.BaseResponse				"Success"
+//	@Failure		400				{object}	web.BaseResponse				"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse				"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse				"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse				"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse				"Internal Server Error"
+//	@Router			/lesson/material/{id} [delete]
+func (l LessonHandlerImpl) DeleteLessonMaterial(w http.ResponseWriter, r *http.Request) {
+	payload := materials.DeleteByUUIDRequestPayload{}
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+
+	payload.DeleteLessonMaterialsToken = token[1]
+	payload.ID = id
+	err = l.LessonService.DeleteLessonMaterial(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
diff --git a/handler/lesson/getLesson.go b/handler/lesson/getLesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..6fe56562324ca2a8e58330ceb1fb593eb09f2301
--- /dev/null
+++ b/handler/lesson/getLesson.go
@@ -0,0 +1,55 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+)
+
+// Index godoc
+//
+//	@Summary		Get lesson by ID
+//	@Description	Retrieve lesson data by UUID
+//	@Tags			lesson
+//	@Produce		json
+//	@Param			id	path		string				true	"Lesson ID (UUID)"
+//	@Success		200	{object}	web.BaseResponse	"Success"
+//	@Failure		400	{object}	web.BaseResponse	"Invalid UUID provided in request path"
+//	@Failure		401	{object}	web.BaseResponse	"Unauthorized"
+//	@Failure		500	{object}	web.BaseResponse	"Internal Server Error"
+//	@Router			/lesson/{id} [get]
+func (l LessonHandlerImpl) GetLesson(w http.ResponseWriter, r *http.Request) {
+	payload := lesson.GetByUUIDRequestPayload{}
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.ID = id
+	packet, err := l.LessonService.GetLesson(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(packet)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/getLessonMaterial.go b/handler/lesson/getLessonMaterial.go
new file mode 100644
index 0000000000000000000000000000000000000000..f6449cd6b95a01cdf6418f47b72849a553cadd12
--- /dev/null
+++ b/handler/lesson/getLessonMaterial.go
@@ -0,0 +1,55 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+// Index godoc
+//
+//	@Summary		Get lesson by ID
+//	@Description	Retrieve lesson data by UUID
+//	@Tags			lesson
+//	@Produce		json
+//	@Param			id	path		string				true	"Lesson ID (UUID)"
+//	@Success		200	{object}	web.BaseResponse	"Success"
+//	@Failure		400	{object}	web.BaseResponse	"Invalid UUID provided in request path"
+//	@Failure		401	{object}	web.BaseResponse	"Unauthorized"
+//	@Failure		500	{object}	web.BaseResponse	"Internal Server Error"
+//	@Router			/lesson/material/{id} [get]
+func (l LessonHandlerImpl) GetLessonMaterial(w http.ResponseWriter, r *http.Request) {
+	payload := materials.GetByUUIDRequestPayload{}
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+	
+	payload.ID = id
+	packet, err := l.LessonService.GetLessonMaterial(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(packet)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/getLessonMaterialsByLesson.go b/handler/lesson/getLessonMaterialsByLesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..dcb37eb5dfee8fd45a338d9a480b17b20c77218b
--- /dev/null
+++ b/handler/lesson/getLessonMaterialsByLesson.go
@@ -0,0 +1,55 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+// Index godoc
+//
+//	@Summary		Get lesson materials by lesson ID
+//	@Description	Retrieve lesson materials data by lesson ID
+//	@Tags			lesson
+//	@Produce		json
+//	@Param			id	path		string				true	"Lesson ID (UUID)"
+//	@Success		200	{object}	web.BaseResponse	"Success"
+//	@Failure		400	{object}	web.BaseResponse	"Invalid UUID provided in request path"
+//	@Failure		401	{object}	web.BaseResponse	"Unauthorized"
+//	@Failure		500	{object}	web.BaseResponse	"Internal Server Error"
+//	@Router			/lesson/material/lesson/{id} [get]
+func (l LessonHandlerImpl) GetLessonMaterialsByLesson(w http.ResponseWriter, r *http.Request) {
+	payload := materials.GetByUUIDRequestPayload{}
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+	
+	payload.ID = id
+	packet, err := l.LessonService.GetLessonMaterials(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(packet)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/getLessonsByCourse.go b/handler/lesson/getLessonsByCourse.go
new file mode 100644
index 0000000000000000000000000000000000000000..fd2956b7f2cd1a90fb428dcd1d7945783c2dfd50
--- /dev/null
+++ b/handler/lesson/getLessonsByCourse.go
@@ -0,0 +1,47 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/go-chi/chi/v5"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+)
+
+// Index godoc
+//
+//	@Summary		Get lesson by course ID
+//	@Description	Retrieve lesson data by course ID
+//	@Tags			lesson
+//	@Produce		json
+//	@Param			id	path		string				true	"Course ID"
+//	@Success		200	{object}	web.BaseResponse	"Success"
+//	@Failure		400	{object}	web.BaseResponse	"Invalid ID provided in request path"
+//	@Failure		401	{object}	web.BaseResponse	"Unauthorized"
+//	@Failure		500	{object}	web.BaseResponse	"Internal Server Error"
+//	@Router			/lesson/course/{id} [get]
+func (l LessonHandlerImpl) GetLessonsByCourse(w http.ResponseWriter, r *http.Request) {
+	payload := lesson.GetByStringRequestPayload{}
+
+	payload.ID = chi.URLParam(r, "id")
+	packet, err := l.LessonService.GetLessons(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[LESSON] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(packet)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/lesson/handler.go b/handler/lesson/handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..874c8ea2727ebf3075a106c7b57eb6dad29ca08e
--- /dev/null
+++ b/handler/lesson/handler.go
@@ -0,0 +1,17 @@
+package lesson
+
+import (
+	r "gitlab.informatika.org/ocw/ocw-backend/repository/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/service/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/httputil"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/wrapper"
+)
+
+type LessonHandlerImpl struct {
+	r.LessonRepository
+	lesson.LessonService
+	httputil.HttpUtil
+	wrapper.WrapperUtil
+	logger.Logger
+}
\ No newline at end of file
diff --git a/handler/lesson/types.go b/handler/lesson/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..f04fef9df33be6d8ab41685f97aec022cbb27e07
--- /dev/null
+++ b/handler/lesson/types.go
@@ -0,0 +1,23 @@
+package lesson
+
+import "net/http"
+
+type LessonHandler interface {
+	// Get
+	GetLesson(w http.ResponseWriter, r *http.Request)
+	GetLessonsByCourse(w http.ResponseWriter, r *http.Request)
+	GetLessonMaterial(w http.ResponseWriter, r *http.Request)
+	GetLessonMaterialsByLesson(w http.ResponseWriter, r *http.Request)
+
+	// Add (Put)
+	AddLesson(w http.ResponseWriter, r *http.Request)
+	AddLessonMaterial(w http.ResponseWriter, r *http.Request)
+
+	// Update
+	UpdateLesson(w http.ResponseWriter, r *http.Request)
+	UpdateLessonMaterial(w http.ResponseWriter, r *http.Request)
+
+	// Delete
+	DeleteLesson(w http.ResponseWriter, r *http.Request)
+	DeleteLessonMaterial(w http.ResponseWriter, r *http.Request)
+}
diff --git a/handler/lesson/updateLesson.go b/handler/lesson/updateLesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..5638be670ce3be0b077dd6b2a9a6fbcee91b6381
--- /dev/null
+++ b/handler/lesson/updateLesson.go
@@ -0,0 +1,114 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/go-playground/validator/v10"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+)
+
+// Index godoc
+//
+//	@Summary		Update a lesson
+//	@Description	Update a lesson with the given ID
+//	@Tags			lesson
+//	@Param			id				path		string								true	"Lesson ID (UUID)"
+//	@Param			payload			body		lesson.UpdateLessonRequestPayload	true	"Update Lesson Payload"
+//	@Param			Authorization	header		string								true	"UpdateLessonToken"
+//	@Success		200				{object}	web.BaseResponse					"Success"
+//	@Failure		400				{object}	web.BaseResponse					"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse					"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse					"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse					"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse					"Internal Server Error"
+//	@Router			/lesson/{id} [patch]
+func (l LessonHandlerImpl) UpdateLesson(w http.ResponseWriter, r *http.Request) {
+	payload := lesson.UpdateLessonRequestPayload{}
+	validate := validator.New()
+
+	// Validate payload
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := l.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := l.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		l.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := l.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.UpdateLessonToken = token[1]
+	payload.ID = id
+	err = l.LessonService.UpdateLesson(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[RESET] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
+
+	
\ No newline at end of file
diff --git a/handler/lesson/updateLessonMaterial.go b/handler/lesson/updateLessonMaterial.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb3689db902d9918de59840e38d76777d02b9543
--- /dev/null
+++ b/handler/lesson/updateLessonMaterial.go
@@ -0,0 +1,114 @@
+package lesson
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/go-playground/validator/v10"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+// Index godoc
+//
+//	@Summary		Update a lesson material
+//	@Description	Update a lesson material with the given ID
+//	@Tags			lesson
+//	@Param			id				path		string								true	"Lesson Material ID (UUID)"
+//	@Param			payload			body		materials.UpdateLessonMaterialsRequestPayload	true	"Update Lesson Materials Payload"
+//	@Param			Authorization	header		string								true	"UpdateLessonMaterialsToken"
+//	@Success		200				{object}	web.BaseResponse					"Success"
+//	@Failure		400				{object}	web.BaseResponse					"Bad Request"
+//	@Failure		401				{object}	web.BaseResponse					"Unauthorized"
+//	@Failure		403				{object}	web.BaseResponse					"Forbidden"
+//	@Failure		422				{object}	web.BaseResponse					"Unprocessable Entity"
+//	@Failure		500				{object}	web.BaseResponse					"Internal Server Error"
+//	@Router			/lesson/{id} [patch]
+func (l LessonHandlerImpl) UpdateLessonMaterial(w http.ResponseWriter, r *http.Request) {
+	payload := materials.UpdateLessonMaterialsRequestPayload{}
+	validate := validator.New()
+
+	// Validate payload
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := l.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		l.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := l.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		l.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := l.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := l.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		l.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	id, err := uuid.Parse(chi.URLParam(r, "id"))
+
+	if err != nil {
+		payload := l.WrapperUtil.ErrorResponseWrap("invalid id", nil)
+		l.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.UpdateLessonMaterialsToken = token[1]
+	payload.ID = id
+	err = l.LessonService.UpdateLessonMaterial(payload)
+
+	if err != nil {
+		if errData, ok := err.(web.ResponseError); ok {
+			payload := l.WrapperUtil.ErrorResponseWrap(errData.Error(), errData)
+			l.HttpUtil.WriteJson(w, http.StatusUnauthorized, payload)
+			return
+		}
+
+		l.Logger.Error(
+			fmt.Sprintf("[RESET] some error happened when validating URL: %s", err.Error()),
+		)
+		payload := l.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		l.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	responsePayload := l.WrapperUtil.SuccessResponseWrap(nil)
+	l.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
+
+	
\ No newline at end of file
diff --git a/handler/quiz/take.go b/handler/quiz/take.go
index 530f4f77823001b1a5027b76d610b8c9ccafcaad..06499ed4839bd8e9ce07d009b3122656d311fb9c 100644
--- a/handler/quiz/take.go
+++ b/handler/quiz/take.go
@@ -138,7 +138,7 @@ func (m QuizHandlerImpl) GetQuizSolution(w http.ResponseWriter, r *http.Request)
 //	@Param			  data	body		quiz.FinishQuizPayload							true	"Quiz Finish payload"
 //	@Param				id path string true "Quiz id" Format(uuid)
 //	@Success			200	{object}	web.BaseResponse{data=quiz.QuizDetail}
-//	@Router				/quiz/{id}/take [post]
+//	@Router				/quiz/{id}/finish [post]
 func (m QuizHandlerImpl) FinishQuiz(w http.ResponseWriter, r *http.Request) {
 	payload := quiz.FinishQuizPayload{}
 
diff --git a/model/domain/course/course.go b/model/domain/course/course.go
index 17d592f2301d2bd0097a7fb465e5b8474b46cc09..f57db686acab2cc98221a5bc9cebf2ae85161843 100644
--- a/model/domain/course/course.go
+++ b/model/domain/course/course.go
@@ -13,7 +13,7 @@ type Major struct {
 	ID           uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
 	Name         string    `json:"name"`
 	Fac_id       uuid.UUID `json:"fac_id" gorm:"type:uuid"`
-	Faculty      *Faculty  `json:"faculty" gorm:"foreignKey:Fac_id"`
+	Faculty      *Faculty  `json:"-" gorm:"foreignKey:Fac_id"`
 	Abbreviation string    `json:"abbreviation"`
 }
 
@@ -21,7 +21,7 @@ type Course struct {
 	ID           string    `json:"id" gorm:"primaryKey"`
 	Name         string    `json:"name"`
 	Major_id     uuid.UUID `json:"major_id" gorm:"type:uuid"`
-	Major        *Major    `json:"major" gorm:"foreignKey:Major_id"`
+	Major        *Major    `json:"-" gorm:"foreignKey:Major_id"`
 	Description  string    `json:"description"`
 	Email        string    `json:"email"`
 	Abbreviation string    `json:"abbreviation"`
diff --git a/model/domain/lesson/lesson.go b/model/domain/lesson/lesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..621295e7dd5bbf7116654a5fef038cca7981e6ab
--- /dev/null
+++ b/model/domain/lesson/lesson.go
@@ -0,0 +1,34 @@
+package lesson
+
+import (
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/course"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/material"
+)
+
+type Lesson struct {
+	ID          uuid.UUID      `json:"id" gorm:"primaryKey;type:uuid"`
+	Name        string         `json:"name"`
+	CourseID    string         `json:"course_id"`
+	Course      *course.Course `json:"-" gorm:"foreignKey:CourseID"`
+	Order       int            `json:"order"`
+	Description string         `json:"description"`
+}
+
+type LessonMaterials struct {
+	ID         uuid.UUID          `json:"id" gorm:"primaryKey;type:uuid"`
+	LessonID   uuid.UUID          `json:"lesson_id"`
+	Lesson     *Lesson            `json:"-" gorm:"foreignKey:LessonID"`
+	Order      int                `json:"order"`
+	MaterialID uuid.UUID          `json:"material_id"`
+	Material   *material.Material `json:"-" gorm:"foreignKey:MaterialID"`
+	Contents   string             `json:"contents"`
+}
+
+func (Lesson) TableName() string {
+	return "lesson"
+}
+
+func (LessonMaterials) TableName() string {
+	return "lesson_materials"
+}
diff --git a/model/web/course/faculty/request.go b/model/web/course/faculty/request.go
index 1c08bddf6fc2410cc7bdec8542c9edc17f5a95e9..2233e13fd7b7232af52e5340b686eb7853721ae0 100644
--- a/model/web/course/faculty/request.go
+++ b/model/web/course/faculty/request.go
@@ -22,7 +22,7 @@ type UpdateFacultyRequestPayload struct {
 	UpdateFacultyToken string
 
 	// Faculty ID, Provided by Query
-	ID uuid.UUID
+	ID uuid.UUID `json:"-" validate:"required"`
 
 	// Faculty Name
 	Name string `json:"name" validate:"required"`
diff --git a/model/web/course/major/request.go b/model/web/course/major/request.go
index 53bc733584b8c437905b7bf7ef9d3a636866262b..1238cbf944d811b7e7c343b174c48974d64faab5 100644
--- a/model/web/course/major/request.go
+++ b/model/web/course/major/request.go
@@ -29,7 +29,7 @@ type UpdateMajorRequestPayload struct {
 	UpdateMajorToken string
 
 	// Major ID, provided by query
-	ID uuid.UUID
+	ID uuid.UUID `json:"-" validate:"required"`
 
 	// Major Name
 	Name string `json:"name" validate:"required"`
diff --git a/model/web/course/request.go b/model/web/course/request.go
index 70bb3c87eae390a9d8050ed4e145653fa38b38be..20b446d8e06a7f4acb316d52e1c16d9e4b4f6607 100644
--- a/model/web/course/request.go
+++ b/model/web/course/request.go
@@ -37,7 +37,7 @@ type DeleteByStringRequestPayload struct {
 	DeleteCourseToken string
 
 	// Course ID, provided by query
-	ID string
+	ID string `json:"-" validate:"required"`
 }
 
 
@@ -45,14 +45,14 @@ type DeleteByStringRequestPayload struct {
 //	@Description	Information that should be available when you get using course id (string)
 type GetByStringRequestPayload struct {
 	// Course ID, provided by query
-	ID string
+	ID string `json:"-" validate:"required"`
 }
 
 // GetUUID Request Payload
 //	@Description	Information that should be available when you get using major/faculty id (string)
 type GetByUUIDRequestPayload struct {
 	// Major/Faculty ID, provided by query
-	ID uuid.UUID
+	ID uuid.UUID `json:"-" validate:"required"`
 }
 
 // UpdateCourse Request Payload
@@ -62,7 +62,7 @@ type UpdateCourseRequestPayload struct {
 	UpdateCourseToken string
 
 	// Course ID, Provided by query
-	ID string `json:"id"`
+	ID string `json:"-" validate:"required"`
 
 	// Course Name
 	Name string `json:"name" validate:"required"`
diff --git a/model/web/lesson/materials/request.go b/model/web/lesson/materials/request.go
new file mode 100644
index 0000000000000000000000000000000000000000..b20dcbb537886cd4704dfa401ffd695da77196ef
--- /dev/null
+++ b/model/web/lesson/materials/request.go
@@ -0,0 +1,63 @@
+package materials
+
+import (
+	"github.com/google/uuid"
+)
+
+// AddLessonMaterials Request Payload
+//	@Description	Information that should be available when you add a lesson material
+type AddLessonMaterialsRequestPayload struct {
+	// Web Token that was appended to the link
+	AddLessonMaterialsToken string
+
+	// Lesson ID
+	LessonID uuid.UUID `json:"lesson_id" validate:"required"`
+
+	// Lesson Material Order
+	Order int `json:"order" validate:"required"`
+
+	// Lesson Material ID, optional
+	MaterialID uuid.UUID `json:"material_id"`
+
+	// Lesson Contents
+	Contents string `json:"contents" validate:"required"`
+}
+
+// DeleteLessonMaterials Request Payload
+//	@Description	Information that should be available when you delete using lesson material id (uuid)
+type DeleteByUUIDRequestPayload struct {
+	// Web Token that was appended to the link
+	DeleteLessonMaterialsToken string
+
+	// Lesson Material ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+}
+
+// UpdateLessonMaterials Request Payload
+//	@Description	Information that should be available when you update a lesson material
+type UpdateLessonMaterialsRequestPayload struct {
+	// Web Token that was appended to the link
+	UpdateLessonMaterialsToken string
+
+	// Lesson Material ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+
+	// Lesson ID
+	LessonID uuid.UUID `json:"lesson_id" validate:"required"`
+
+	// Lesson Material Order
+	Order int `json:"order" validate:"required"`
+
+	// Lesson Material ID, optional
+	MaterialID uuid.UUID `json:"material_id"`
+
+	// Lesson Contents
+	Contents string `json:"contents" validate:"required"`
+}
+
+// GetUUID Request Payload
+//	@Description	Information that should be available when you get using id or lesson id (uuid)
+type GetByUUIDRequestPayload struct {
+	// Lesson ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+}
\ No newline at end of file
diff --git a/model/web/lesson/request.go b/model/web/lesson/request.go
new file mode 100644
index 0000000000000000000000000000000000000000..4a999f7d45320e58d51a3bf4bbd18947f9a5c991
--- /dev/null
+++ b/model/web/lesson/request.go
@@ -0,0 +1,68 @@
+package lesson
+
+import "github.com/google/uuid"
+
+// AddLesson Request Payload
+//	@Description	Information that should be available when you add a lesson
+type AddLessonRequestPayload struct {
+	// Web Token that was appended to the link
+	AddLessonToken string
+
+	// Lesson Name
+	Name string `json:"name" validate:"required"`
+
+	// Course ID
+	CourseID string `json:"course_id" validate:"required"`
+	
+	// Lesson Order
+	Order int `json:"order" validate:"required"`
+
+	// Lesson Description (Can be left empty)
+	Description string `json:"description"`
+}
+
+// DeleteLesson Request Payload
+//	@Description	Information that should be available when you delete using lesson id (uuid)
+type DeleteByUUIDRequestPayload struct {
+	// Web Token that was appended to the link
+	DeleteLessonToken string
+
+	// Lesson ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+}
+
+// UpdateLesson Request Payload
+//	@Description	Information that should be available when you update a lesson
+type UpdateLessonRequestPayload struct {
+	// Web Token that was appended to the link
+	UpdateLessonToken string
+
+	// Lesson ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+
+	// Lesson Name
+	Name string `json:"name" validate:"required"`
+
+	// Course ID
+	CourseID string `json:"course_id" validate:"required"`
+
+	// Lesson Order
+	Order int `json:"order" validate:"required"`
+
+	// Lesson Description (Can be left empty)
+	Description string `json:"description"`
+}
+
+// GetUUID Request Payload
+//	@Description	Information that should be available when you get using lesson id (uuid)
+type GetByUUIDRequestPayload struct {
+	// Lesson ID, provided by query
+	ID uuid.UUID `json:"-" validate:"required"`
+}
+
+// GetID Request Payload
+//	@Description	Information that should be available when you get using course id (string)
+type GetByStringRequestPayload struct {
+	// Course ID, provided by query
+	ID string `json:"-" validate:"required"`
+}
diff --git a/provider/mail/smtp/smtp.go b/provider/mail/smtp/smtp.go
index cc1d4060a460ed00840c8f52072ee2ee7b20234f..0dacbabc2f84bf2effb400ce67e9ec46ab397e1c 100644
--- a/provider/mail/smtp/smtp.go
+++ b/provider/mail/smtp/smtp.go
@@ -13,10 +13,20 @@ type SmtpMailProvider struct {
 }
 
 func New(env *env.Environment) *SmtpMailProvider {
-	auth := smtp.CRAMMD5Auth(
-		env.SmtpUsername,
-		env.SmtpPassword,
-	)
+	var auth smtp.Auth
+	if env.SmtpAuthType == "CRAM" {
+		auth = smtp.CRAMMD5Auth(
+			env.SmtpUsername,
+			env.SmtpPassword,
+		)
+	} else if env.SmtpAuthType == "plain" {
+		auth = smtp.PlainAuth(
+			env.SmtpIdentity,
+			env.SmtpUsername,
+			env.SmtpPassword,
+			env.SmtpServer,
+		)
+	}
 
 	return &SmtpMailProvider{
 		Environment: env,
diff --git a/provider/redis/cache.go b/provider/redis/cache.go
index 9d656ae2093191e41cdd8666e7f20f5b2c185a92..729c3e4f82cffd75685eb44160f5754695da93e9 100644
--- a/provider/redis/cache.go
+++ b/provider/redis/cache.go
@@ -43,23 +43,29 @@ func NewRedisEnv(
 			IdleTimeout: 240 * time.Second,
 			Dial: func() (redis.Conn, error) {
 				defer resolver(log)
-				conn, err := redis.Dial("tcp", env.RedisConnection+":"+env.RedisPort)
 
-				if err != nil {
-					log.Warning("failed connect to redis server: tcp " + env.RedisConnection + ":" + env.RedisPort)
-					log.Warning(err.Error())
-
-					return nil, err
+				dialOptions := []redis.DialOption{
+					redis.DialUseTLS(env.RedisUseTLS),
 				}
 
 				if env.RedisUseAuth {
-					if _, err := conn.Do("AUTH", env.RedisUsername, env.RedisPassword); err != nil {
-						conn.Close()
+					dialOptions = append(dialOptions,
+						redis.DialUsername(env.RedisUsername),
+						redis.DialPassword(env.RedisPassword),
+					)
+				}
 
-						log.Warning("failed connect to redis server: authentication failed")
+				conn, err := redis.Dial(
+					"tcp",
+					env.RedisConnection+":"+env.RedisPort,
+					dialOptions...,
+				)
 
-						return nil, err
-					}
+				if err != nil {
+					log.Warning("failed connect to redis server: tcp " + env.RedisConnection + ":" + env.RedisPort)
+					log.Warning(err.Error())
+
+					return nil, err
 				}
 
 				return conn, err
diff --git a/provider/storage/manager.go b/provider/storage/manager.go
index cfeae57144fe4d23729a2382984360253e5d4659..6cf93f7291323ebb26246670dcafd9978aeda76f 100644
--- a/provider/storage/manager.go
+++ b/provider/storage/manager.go
@@ -1,7 +1,10 @@
 package storage
 
 import (
+	"bufio"
+	"bytes"
 	"context"
+	"io"
 
 	"github.com/minio/minio-go/v7"
 )
@@ -18,7 +21,15 @@ func (s S3Storage) Get(ctx context.Context, path string) ([]byte, error) {
 		return result, err
 	}
 
-	_, err = obj.Read(result)
+	var buffer bytes.Buffer
+	writter := bufio.NewWriter(&buffer)
+
+	_, err = io.Copy(writter, obj)
+	if err != nil {
+		return result, err
+	}
+
+	result = buffer.Bytes()
 
 	return result, err
 }
diff --git a/repository/di.go b/repository/di.go
index b564bd5406f7d94427c5c0f80ccc518bc23fd5b2..9a418dca489cf4056d66d76510015e9f79f0b3cd 100644
--- a/repository/di.go
+++ b/repository/di.go
@@ -5,6 +5,7 @@ import (
 	"gitlab.informatika.org/ocw/ocw-backend/repository/cache"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/content"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/course"
+	"gitlab.informatika.org/ocw/ocw-backend/repository/lesson"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/material"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/transaction"
@@ -24,6 +25,13 @@ var RepositoryBasicSet = wire.NewSet(
 	cache.New,
 	wire.Bind(new(cache.CacheRepository), new(*cache.CacheRepositoryImpl)),
 
+	// Lesson Repository
+	lesson.NewLesson,
+	lesson.NewLessonMaterials,
+	wire.Bind(new(lesson.LessonRepository), new(*lesson.LessonRepositoryImpl)),
+	wire.Bind(new(lesson.LessonMaterialsRepository), new(*lesson.LessonMaterialsRepositoryImpl)),
+
+	// Material Repository
 	material.NewMaterial,
 	material.NewMaterialContent,
 
diff --git a/repository/lesson/lesson.go b/repository/lesson/lesson.go
new file mode 100644
index 0000000000000000000000000000000000000000..e3e1002320c10381a8bad1386da2f3e78eb04c22
--- /dev/null
+++ b/repository/lesson/lesson.go
@@ -0,0 +1,52 @@
+package lesson
+
+import (
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/provider/db"
+	"gorm.io/gorm"
+)
+
+type LessonRepositoryImpl struct {
+	db *gorm.DB
+}
+
+func NewLesson(
+	db db.Database,
+) *LessonRepositoryImpl {
+	return &LessonRepositoryImpl{db.Connect()}
+}
+
+func (repo LessonRepositoryImpl) GetLesson(id uuid.UUID) (*lesson.Lesson, error) {
+	result := &lesson.Lesson{}
+	err := repo.db.First(result, "id = ?", id).Error
+
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func (repo LessonRepositoryImpl) GetLessons(courseId string) ([]lesson.Lesson, error) {
+	var result []lesson.Lesson
+	err := repo.db.Where("course_id = ?", courseId).Find(&result).Error
+
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func (repo LessonRepositoryImpl) AddLesson(lesson lesson.Lesson) error {
+	return repo.db.Create(lesson).Error
+}
+
+func (repo LessonRepositoryImpl) UpdateLesson(lesson lesson.Lesson) error {
+	return repo.db.Save(lesson).Error
+}
+
+func (repo LessonRepositoryImpl) DeleteLesson(id uuid.UUID) error {
+	return repo.db.Delete(&lesson.Lesson{}, id).Error
+}
diff --git a/repository/lesson/materials.go b/repository/lesson/materials.go
new file mode 100644
index 0000000000000000000000000000000000000000..d0e5ea70a634f4283a8c164089013f5249c55ff7
--- /dev/null
+++ b/repository/lesson/materials.go
@@ -0,0 +1,52 @@
+package lesson
+
+import (
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/provider/db"
+	"gorm.io/gorm"
+)
+
+type LessonMaterialsRepositoryImpl struct {
+	db *gorm.DB
+}
+
+func NewLessonMaterials(
+	db db.Database,
+) *LessonMaterialsRepositoryImpl {
+	return &LessonMaterialsRepositoryImpl{db.Connect()}
+}
+
+func (repo LessonMaterialsRepositoryImpl) GetLessonMaterial(id uuid.UUID) (*lesson.LessonMaterials, error) {
+	result := &lesson.LessonMaterials{}
+	err := repo.db.First(result, "id = ?", id).Error
+
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func (repo LessonMaterialsRepositoryImpl) GetLessonMaterials(lessonId uuid.UUID) ([]lesson.LessonMaterials, error) {
+	var result []lesson.LessonMaterials
+	err := repo.db.Where("lesson_id = ?", lessonId).Find(&result).Error
+
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+func (repo LessonMaterialsRepositoryImpl) AddLessonMaterial(lessonMaterial lesson.LessonMaterials) error {
+	return repo.db.Create(lessonMaterial).Error
+}
+
+func (repo LessonMaterialsRepositoryImpl) UpdateLessonMaterial(lessonMaterial lesson.LessonMaterials) error {
+	return repo.db.Save(lessonMaterial).Error
+}
+
+func (repo LessonMaterialsRepositoryImpl) DeleteLessonMaterial(id uuid.UUID) error {
+	return repo.db.Delete(&lesson.LessonMaterials{}, id).Error
+}
diff --git a/repository/lesson/type.go b/repository/lesson/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..4925c016cd2ed78e256a31fb5166a2c1c2ab828e
--- /dev/null
+++ b/repository/lesson/type.go
@@ -0,0 +1,22 @@
+package lesson
+
+import (
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"github.com/google/uuid"
+)
+
+type LessonRepository interface {
+	GetLesson(id uuid.UUID) (*lesson.Lesson, error)
+	GetLessons(courseId string) ([]lesson.Lesson, error)
+	AddLesson(lesson lesson.Lesson) error
+	UpdateLesson(lesson lesson.Lesson) error
+	DeleteLesson(id uuid.UUID) error
+}
+
+type LessonMaterialsRepository interface {
+	GetLessonMaterial(id uuid.UUID) (*lesson.LessonMaterials, error)
+	GetLessonMaterials(lessonId uuid.UUID) ([]lesson.LessonMaterials, error)
+	AddLessonMaterial(lessonMaterial lesson.LessonMaterials) error
+	UpdateLessonMaterial(lessonMaterial lesson.LessonMaterials) error
+	DeleteLessonMaterial(id uuid.UUID) error
+}
\ No newline at end of file
diff --git a/repository/quiz/impl.go b/repository/quiz/impl.go
index 36818e4404952060419553ef34c205bc14f7a8f1..e43a00e03f3fe6348d69ed92a88cee1b7aad8706 100644
--- a/repository/quiz/impl.go
+++ b/repository/quiz/impl.go
@@ -43,9 +43,11 @@ func (q *QuizRepositoryImpl) GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error)
 func (q *QuizRepositoryImpl) UpdateScore(takeId uuid.UUID, score int) error {
 	return q.db.
 		Model(&quiz.QuizTake{}).
-		Update("score", score).
-		Update("is_finished", true).
-		Where("id = ?", takeId).Error
+		Where("id = ?", takeId).
+		Updates(quiz.QuizTake{
+			Score:      score,
+			IsFinished: true,
+		}).Error
 }
 
 func (q *QuizRepositoryImpl) NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error) {
@@ -94,18 +96,18 @@ func(q *QuizRepositoryImpl) Delete(quizId uuid.UUID) error {
 }
 
 func (q *QuizRepositoryImpl) IsActiveTake(quizId uuid.UUID, userEmail string) (bool, error) {
-	result := struct{ cnt int }{}
+	var result int64 = 0
 	err := q.db.
-		Select("COUNT(*) as cnt").
+		Model(&quiz.QuizTake{}).
 		Where("quiz_id = ? AND email = ? AND is_finished = false", quizId, userEmail).
-		Find(result).
+		Count(&result).
 		Error
 
 	if err != nil {
 		return false, nil
 	}
 
-	return result.cnt > 0, nil
+	return result > 0, nil
 }
 
 func (q *QuizRepositoryImpl) GetAllTake(quizId uuid.UUID, userEmail string) ([]quiz.QuizTake, error) {
diff --git a/routes/di.go b/routes/di.go
index ddae40f95c5cde473aadc4f6d26a357c98b5f089..d3129d33efdd8101223d47acb66efa1cd5bd5c73 100644
--- a/routes/di.go
+++ b/routes/di.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.informatika.org/ocw/ocw-backend/routes/auth"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/common"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/course"
+	"gitlab.informatika.org/ocw/ocw-backend/routes/lesson"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/material"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/reset"
@@ -19,6 +20,7 @@ var routesCollectionSet = wire.NewSet(
 	wire.Struct(new(admin.AdminRoutes), "*"),
 	wire.Struct(new(reset.ResetRoutes), "*"),
 	wire.Struct(new(course.CourseRoutes), "*"),
+	wire.Struct(new(lesson.LessonRoutes), "*"),
 	wire.Struct(new(material.MaterialRoutes), "*"),
 	wire.Struct(new(quiz.QuizRoutes), "*"),
 )
diff --git a/routes/lesson/route.go b/routes/lesson/route.go
new file mode 100644
index 0000000000000000000000000000000000000000..7d19720c746d2a88b4dcb5bb70079bed7bced2db
--- /dev/null
+++ b/routes/lesson/route.go
@@ -0,0 +1,28 @@
+package lesson
+
+import (
+	"github.com/go-chi/chi/v5"
+	"gitlab.informatika.org/ocw/ocw-backend/handler/lesson"
+)
+
+type LessonRoutes struct {
+	lesson.LessonHandler
+}
+
+func (l LessonRoutes) Register(r chi.Router) {
+	r.Route("/lesson", func(r chi.Router) {
+		r.Get("/{id}", l.LessonHandler.GetLesson)
+		r.Get("/course/{id}", l.LessonHandler.GetLessonsByCourse)
+		r.Get("/material/{id}", l.LessonHandler.GetLessonMaterial)
+		r.Get("/material/lesson/{id}", l.LessonHandler.GetLessonMaterialsByLesson)
+
+		r.Put("/", l.LessonHandler.AddLesson)
+		r.Put("/material", l.LessonHandler.AddLessonMaterial)
+
+		r.Post("/{id}", l.LessonHandler.UpdateLesson)
+		r.Post("/material/{id}", l.LessonHandler.UpdateLessonMaterial)
+
+		r.Delete("/{id}", l.LessonHandler.DeleteLesson)
+		r.Delete("/material/{id}", l.LessonHandler.DeleteLessonMaterial)
+	})
+}
diff --git a/routes/routes.go b/routes/routes.go
index 096f4d5005e2bfe01f82bfe53552edc99b1d0258..34e2036236b737b7b48fd6d1ad026925a4495681 100644
--- a/routes/routes.go
+++ b/routes/routes.go
@@ -5,6 +5,7 @@ import (
 	"gitlab.informatika.org/ocw/ocw-backend/routes/auth"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/common"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/course"
+	"gitlab.informatika.org/ocw/ocw-backend/routes/lesson"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/material"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/routes/reset"
@@ -22,6 +23,7 @@ type AppRouter struct {
 	reset.ResetRoutes
 	quiz.QuizRoutes
 	course.CourseRoutes
+	lesson.LessonRoutes
 	material.MaterialRoutes
 
 	// Utility
diff --git a/service/auth/impl.go b/service/auth/impl.go
index 9ac5f343fb68b92e44a3a51491389a21d5c70c5a..5175a0a02b2b13654f7f1328a131fb97447ea432 100644
--- a/service/auth/impl.go
+++ b/service/auth/impl.go
@@ -2,6 +2,7 @@ package auth
 
 import (
 	"gitlab.informatika.org/ocw/ocw-backend/repository/user"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
 	"gitlab.informatika.org/ocw/ocw-backend/service/verification"
 	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
 	"gitlab.informatika.org/ocw/ocw-backend/utils/password"
@@ -14,4 +15,5 @@ type AuthServiceImpl struct {
 	*env.Environment
 	token.TokenUtil
 	verification.VerificationService
+	logger.Logger
 }
diff --git a/service/auth/register.go b/service/auth/register.go
index b7941c50ba99c941bd7810ad82f3c3862f9ef26c..5227bd811d8e9631c09d38f19d4cfef9c364fc45 100644
--- a/service/auth/register.go
+++ b/service/auth/register.go
@@ -1,8 +1,11 @@
 package auth
 
 import (
+	"errors"
+
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
 	"gitlab.informatika.org/ocw/ocw-backend/model/web/auth/register"
+	"gorm.io/gorm"
 )
 
 func (auth AuthServiceImpl) Register(payload register.RegisterRequestPayload) error {
@@ -20,8 +23,19 @@ func (auth AuthServiceImpl) Register(payload register.RegisterRequestPayload) er
 		IsActivated: false,
 	})
 
+	if errors.Is(err, gorm.ErrDuplicatedKey) {
+		err := auth.SendVerifyMail(payload.Email)
+		if err != nil {
+			auth.Logger.Warning("Failed to send email: " + err.Error())
+		}
+		return nil
+	}
+
 	if err == nil {
-		auth.SendVerifyMail(payload.Email)
+		err := auth.SendVerifyMail(payload.Email)
+		if err != nil {
+			auth.Logger.Warning("Failed to send email: " + err.Error())
+		}
 	}
 
 	return err
diff --git a/service/di.go b/service/di.go
index 3a133f5fc0ccdaba5c7260c52fa6a068306cf8a2..88695f660eade6c4efbaedb4ec8e9265ee283848 100644
--- a/service/di.go
+++ b/service/di.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.informatika.org/ocw/ocw-backend/service/auth"
 	"gitlab.informatika.org/ocw/ocw-backend/service/common"
 	"gitlab.informatika.org/ocw/ocw-backend/service/course"
+	"gitlab.informatika.org/ocw/ocw-backend/service/lesson"
 	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
 	"gitlab.informatika.org/ocw/ocw-backend/service/logger/hooks"
 	"gitlab.informatika.org/ocw/ocw-backend/service/material"
@@ -71,6 +72,12 @@ var ServiceTestSet = wire.NewSet(
 		wire.Struct(new(quiz.QuizServiceImpl), "*"),
 		wire.Bind(new(quiz.QuizService), new(*quiz.QuizServiceImpl)),
 	),
+
+	// Lesson Service
+	wire.NewSet(
+		wire.Struct(new(lesson.LessonServiceImpl), "*"),
+		wire.Bind(new(lesson.LessonService), new(*lesson.LessonServiceImpl)),
+	),
 )
 
 var ServiceSet = wire.NewSet(
diff --git a/service/lesson/add.go b/service/lesson/add.go
new file mode 100644
index 0000000000000000000000000000000000000000..9258dcb250ce93be1249a0744ceff4268caebb94
--- /dev/null
+++ b/service/lesson/add.go
@@ -0,0 +1,68 @@
+package lesson
+
+import (
+	domLesson "gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/auth/token"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+func (l LessonServiceImpl) AddLesson(payload lesson.AddLessonRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.AddLessonToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonRepository.AddLesson(domLesson.Lesson{
+		Name:        payload.Name,
+		CourseID:    payload.CourseID,
+		Order:       payload.Order,
+		Description: payload.Description,
+	})
+
+	if err != nil {
+		// Some uncaught error
+		return err
+	}
+
+	return nil
+}
+
+func (l LessonServiceImpl) AddLessonMaterial(payload materials.AddLessonMaterialsRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.AddLessonMaterialsToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonMaterialsRepository.AddLessonMaterial(domLesson.LessonMaterials{
+		LessonID:   payload.LessonID,
+		Order:      payload.Order,
+		MaterialID: payload.MaterialID,
+		Contents:   payload.Contents,
+	})
+
+	if err != nil {
+		// Some uncaught error
+		return err
+	}
+
+	return nil
+}
diff --git a/service/lesson/delete.go b/service/lesson/delete.go
new file mode 100644
index 0000000000000000000000000000000000000000..187b6d07aa07bf103a83b1e21639e1843066247e
--- /dev/null
+++ b/service/lesson/delete.go
@@ -0,0 +1,57 @@
+package lesson
+
+import (
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/auth/token"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+func (l LessonServiceImpl) DeleteLesson(payload lesson.DeleteByUUIDRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.DeleteLessonToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonRepository.DeleteLesson(payload.ID)
+
+	if err != nil {
+		// Uncaught error
+		return err
+	}
+
+	return nil
+}
+
+func (l LessonServiceImpl) DeleteLessonMaterial(payload materials.DeleteByUUIDRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.DeleteLessonMaterialsToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonMaterialsRepository.DeleteLessonMaterial(payload.ID)
+
+	if err != nil {
+		// Uncaught error
+		return err
+	}
+
+	return nil
+}
\ No newline at end of file
diff --git a/service/lesson/get.go b/service/lesson/get.go
new file mode 100644
index 0000000000000000000000000000000000000000..3b3798b2057cb51ec65c7d5a2e297de7fa16d4d5
--- /dev/null
+++ b/service/lesson/get.go
@@ -0,0 +1,67 @@
+package lesson
+
+import (
+	"errors"
+
+	domLesson "gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+	"gorm.io/gorm"
+)
+
+func (l LessonServiceImpl) GetLesson(payload lesson.GetByUUIDRequestPayload) (*domLesson.Lesson, error) {
+	packet, err := l.LessonRepository.GetLesson(payload.ID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, web.NewResponseErrorFromError(err, web.LessonNotExist)
+		}
+		// Some Uncaught error
+		return nil, err
+	}
+	
+	return packet, nil
+}
+
+func (l LessonServiceImpl) GetLessons(payload lesson.GetByStringRequestPayload) ([]domLesson.Lesson, error) {
+	packet, err := l.LessonRepository.GetLessons(payload.ID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, web.NewResponseErrorFromError(err, web.LessonNotExist)
+		}
+		// Some Uncaught error
+		return nil, err
+	}
+	
+	return packet, nil
+}
+
+func (l LessonServiceImpl) GetLessonMaterial(payload materials.GetByUUIDRequestPayload) (*domLesson.LessonMaterials, error) {
+	packet, err := l.LessonMaterialsRepository.GetLessonMaterial(payload.ID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, web.NewResponseErrorFromError(err, web.LessonMaterialNotExist)
+		}
+		// Some Uncaught error
+		return nil, err
+	}
+	
+	return packet, nil
+}
+
+func (l LessonServiceImpl) GetLessonMaterials(payload materials.GetByUUIDRequestPayload) ([]domLesson.LessonMaterials, error) {
+	packet, err := l.LessonMaterialsRepository.GetLessonMaterials(payload.ID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, web.NewResponseErrorFromError(err, web.LessonMaterialNotExist)
+		}
+		// Some Uncaught error
+		return nil, err
+	}
+	
+	return packet, nil
+}
\ No newline at end of file
diff --git a/service/lesson/impl.go b/service/lesson/impl.go
new file mode 100644
index 0000000000000000000000000000000000000000..835b27ac03d42afce5757b6d1efba11282f9986b
--- /dev/null
+++ b/service/lesson/impl.go
@@ -0,0 +1,16 @@
+package lesson
+
+import (
+	"gitlab.informatika.org/ocw/ocw-backend/repository/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/token"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
+)
+
+type LessonServiceImpl struct {
+	lesson.LessonRepository
+	lesson.LessonMaterialsRepository
+	*env.Environment
+	token.TokenUtil
+	logger.Logger
+}
\ No newline at end of file
diff --git a/service/lesson/type.go b/service/lesson/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..3cdae1a02a5eb6cf2bf5961bb2a917114736dc57
--- /dev/null
+++ b/service/lesson/type.go
@@ -0,0 +1,20 @@
+package lesson
+
+import (
+	domLesson "gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+)
+
+type LessonService interface {
+	GetLesson(payload lesson.GetByUUIDRequestPayload) (*domLesson.Lesson, error)
+	GetLessons(payload lesson.GetByStringRequestPayload) ([]domLesson.Lesson, error)
+	AddLesson(payload lesson.AddLessonRequestPayload) error
+	UpdateLesson(payload lesson.UpdateLessonRequestPayload) error
+	DeleteLesson(payload lesson.DeleteByUUIDRequestPayload) error
+	GetLessonMaterial(payload materials.GetByUUIDRequestPayload) (*domLesson.LessonMaterials, error)
+	GetLessonMaterials(payload materials.GetByUUIDRequestPayload) ([]domLesson.LessonMaterials, error)
+	AddLessonMaterial(payload materials.AddLessonMaterialsRequestPayload) error
+	UpdateLessonMaterial(payload materials.UpdateLessonMaterialsRequestPayload) error
+	DeleteLessonMaterial(payload materials.DeleteByUUIDRequestPayload) error
+}
\ No newline at end of file
diff --git a/service/lesson/update.go b/service/lesson/update.go
new file mode 100644
index 0000000000000000000000000000000000000000..4d80a4e10675c9f42a18bd153ec03c4f3487ecd0
--- /dev/null
+++ b/service/lesson/update.go
@@ -0,0 +1,79 @@
+package lesson
+
+import (
+	"errors"
+
+	domLesson "gitlab.informatika.org/ocw/ocw-backend/model/domain/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/auth/token"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/lesson/materials"
+	"gorm.io/gorm"
+)
+
+func (l LessonServiceImpl) UpdateLesson(payload lesson.UpdateLessonRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.UpdateLessonToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonRepository.UpdateLesson(domLesson.Lesson{
+		ID:          payload.ID,
+		Name:        payload.Name,
+		CourseID:    payload.CourseID,
+		Order:       payload.Order,
+		Description: payload.Description,
+	})
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return web.NewResponseErrorFromError(err, web.LessonNotExist)
+		}
+		// Uncaught error
+		return err
+	}
+
+	return nil
+}
+
+func (l LessonServiceImpl) UpdateLessonMaterial(payload materials.UpdateLessonMaterialsRequestPayload) error {
+	// Validate Role
+	claim, err := l.TokenUtil.Validate(payload.UpdateLessonMaterialsToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == user.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	err = l.LessonMaterialsRepository.UpdateLessonMaterial(domLesson.LessonMaterials{
+		ID:         payload.ID,
+		LessonID:   payload.LessonID,
+		Order:      payload.Order,
+		MaterialID: payload.MaterialID,
+		Contents:   payload.Contents,
+	})
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return web.NewResponseErrorFromError(err, web.LessonMaterialNotExist)
+		}
+		// Uncaught error
+		return err
+	}
+
+	return nil
+}
diff --git a/test/mail/mail_test.go b/test/mail/mail_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1f1f48e7d346dbb06ca453c27e48d24364e8e7e0
--- /dev/null
+++ b/test/mail/mail_test.go
@@ -0,0 +1,24 @@
+package mail
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"gitlab.informatika.org/ocw/ocw-backend/provider/mail/smtp"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
+)
+
+func IgnoreTestSendMail(t *testing.T) {
+	smtpClient := smtp.New(&env.Environment{
+		SmtpUsername: "",
+		SmtpPassword: "",
+		SmtpIdentity: "",
+		SmtpServer:   "",
+		SmtpPort:     22,
+		SmtpAuthType: "",
+	})
+
+	err := smtpClient.Send([]string{"bayusamudra.55.02.com@gmail.com"}, "Testing", "Ini test")
+
+	assert.Nil(t, err)
+}
diff --git a/test/middleware/cors_test.go b/test/middleware/cors_test.go
index 74615aa27d9b04bcb60edf4173e0bf9f83b9eddf..b793862aed471c20d8332eab34efdf0bc1dc2e53 100644
--- a/test/middleware/cors_test.go
+++ b/test/middleware/cors_test.go
@@ -16,14 +16,14 @@ func TestPreflight(t *testing.T) {
 			Headers: map[string]string{
 				"Access-Control-Request-Method":  "GET",
 				"Access-Control-Request-Headers": "accept, origin, authorization, content-type, referer",
-				"Origin":                         "https://inkubatorit.com",
+				"Origin":                         "https://test.com",
 			},
 		})
 
 		assert.Nil(t, err)
 
 		assert.Equal(t, res.StatusCode, http.StatusOK)
-		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://inkubatorit.com")
+		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://test.com")
 		assert.Contains(t, res.Header.Get("Access-Control-Allow-Methods"), "GET")
 	})
 
@@ -34,14 +34,14 @@ func TestPreflight(t *testing.T) {
 			Headers: map[string]string{
 				"Access-Control-Request-Method":  "GET",
 				"Access-Control-Request-Headers": "accept, origin, authorization, content-type, referer",
-				"Origin":                         "https://inkubatorit.com",
+				"Origin":                         "https://test.com",
 			},
 		})
 
 		assert.Nil(t, err)
 
 		assert.Equal(t, res.StatusCode, http.StatusOK)
-		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://inkubatorit.com")
+		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://test.com")
 		assert.Contains(t, res.Header.Get("Access-Control-Allow-Methods"), "GET")
 	})
 
@@ -52,14 +52,14 @@ func TestPreflight(t *testing.T) {
 			Headers: map[string]string{
 				"Access-Control-Request-Method":  "PATCH",
 				"Access-Control-Request-Headers": "accept, origin, authorization, content-type, referer",
-				"Origin":                         "https://inkubatorit.com",
+				"Origin":                         "https://test.com",
 			},
 		})
 
 		assert.Nil(t, err)
 
 		assert.Equal(t, res.StatusCode, http.StatusOK)
-		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://inkubatorit.com")
+		assert.Equal(t, res.Header.Get("Access-Control-Allow-Origin"), "https://test.com")
 		assert.Equal(t, res.Header.Get("Access-Control-Allow-Methods"), "PATCH")
 	})
 }
diff --git a/utils/env/env.go b/utils/env/env.go
index 729a7f253d1aaecae0f9c3cf2f06ba1a900a8b6f..50c73820d065affd17ec2d93bf420f994281bdcd 100644
--- a/utils/env/env.go
+++ b/utils/env/env.go
@@ -36,6 +36,7 @@ type Environment struct {
 	SmtpPassword string `env:"SMTP_PASSWORD"`
 	SmtpServer   string `env:"SMTP_SERVER"`
 	SmtpPort     int    `env:"SMTP_PORT" envDefault:"25"`
+	SmtpAuthType string `env:"SMTP_TYPE" envDefault:"CRAM"`
 
 	FrontendBaseURL   string `env:"FE_BASE_URL"`
 	ResetPasswordPath string `env:"RESET_PASSWORD_PATH" envDefault:"/resetPassword"`
@@ -51,6 +52,7 @@ type Environment struct {
 	RedisPassword   string `env:"REDIS_PASSWORD"`
 	RedisUseAuth    bool   `env:"REDIS_USE_AUTH" envDefault:"false"`
 	RedisPrefixKey  string `env:"REDIS_PREFIX_KEY" envDefault:"app:"`
+	RedisUseTLS     bool   `env:"REDIS_USE_TLS" envDefault:"false"`
 
 	BucketEndpoint  string `env:"BUCKET_ENDPOINT"`
 	BucketSecretKey string `env:"BUCKET_SECRET_KEY"`