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 49b75f3556829fa1845dddc0737e82c9ab85bc01..f8ef591bbbb23cab393505ca805d22079e34632e 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1488,6 +1488,540 @@ const docTemplate = `{
                 }
             }
         },
+        "/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",
@@ -1531,9 +2065,210 @@ const docTemplate = `{
                         }
                     }
                 }
-            },
-            "post": {
-                "description": "Add content of 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
+                    },
+                    {
+                        "description": "Add Quiz payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.AddQuizRequestPayload"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz/{id}": {
+            "get": {
+                "description": "Get Quiz Detail",
                 "consumes": [
                     "application/json"
                 ],
@@ -1541,30 +2276,14 @@ const docTemplate = `{
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Add Content",
+                "summary": "Get Quiz Detail",
                 "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",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1582,29 +2301,17 @@ const docTemplate = `{
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "$ref": "#/definitions/material.NewContentResponse"
+                                            "$ref": "#/definitions/quiz.Quiz"
                                         }
                                     }
                                 }
                             ]
                         }
-                    },
-                    "400": {
-                        "description": "Bad Request",
-                        "schema": {
-                            "$ref": "#/definitions/web.BaseResponse"
-                        }
-                    },
-                    "401": {
-                        "description": "Unauthorized",
-                        "schema": {
-                            "$ref": "#/definitions/web.BaseResponse"
-                        }
                     }
                 }
             },
             "delete": {
-                "description": "Delete material",
+                "description": "Delete Quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1612,21 +2319,14 @@ const docTemplate = `{
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Delete material",
+                "summary": "Delete Quiz",
                 "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Access token",
-                        "name": "Authorization",
-                        "in": "header",
-                        "required": true
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
-                        "description": "Material id",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1640,11 +2340,9 @@ const docTemplate = `{
                         }
                     }
                 }
-            }
-        },
-        "/material/{id}/content/{content-id}": {
-            "delete": {
-                "description": "Delete content of material",
+            },
+            "patch": {
+                "description": "Update Quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1652,32 +2350,26 @@ const docTemplate = `{
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Delete Content",
+                "summary": "Update Quiz",
                 "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Access token",
-                        "name": "Authorization",
-                        "in": "header",
-                        "required": true
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
-                        "description": "Material id",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
                     },
                     {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Content id",
-                        "name": "content-id",
-                        "in": "path",
-                        "required": true
+                        "description": "Update Quiz payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.UpdateQuizRequestPayload"
+                        }
                     }
                 ],
                 "responses": {
@@ -1690,9 +2382,9 @@ const docTemplate = `{
                 }
             }
         },
-        "/quiz/{id}": {
-            "get": {
-                "description": "Get Quiz Detail",
+        "/quiz/{id}/finish": {
+            "post": {
+                "description": "Finish quiz session and get the score",
                 "consumes": [
                     "application/json"
                 ],
@@ -1702,8 +2394,24 @@ const docTemplate = `{
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Get Quiz Detail",
+                "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",
@@ -1725,7 +2433,7 @@ const docTemplate = `{
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "$ref": "#/definitions/quiz.Quiz"
+                                            "$ref": "#/definitions/quiz.QuizDetail"
                                         }
                                     }
                                 }
@@ -1789,7 +2497,7 @@ const docTemplate = `{
         },
         "/quiz/{id}/take": {
             "post": {
-                "description": "Finish quiz session and get the score",
+                "description": "Take a quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1799,7 +2507,7 @@ const docTemplate = `{
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Finish Quiz",
+                "summary": "Take Quiz",
                 "parameters": [
                     {
                         "type": "string",
@@ -1808,15 +2516,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",
@@ -2026,7 +2725,6 @@ const docTemplate = `{
             "description": "Information that should be available when you add a course",
             "type": "object",
             "required": [
-                "abbreviation",
                 "email",
                 "id",
                 "name"
@@ -2053,6 +2751,10 @@ const docTemplate = `{
                     "description": "Course ID",
                     "type": "string"
                 },
+                "lecturer": {
+                    "description": "Course Lecturer Name",
+                    "type": "string"
+                },
                 "majabbr": {
                     "description": "Course Major Abbreviation",
                     "type": "string"
@@ -2071,9 +2773,7 @@ const docTemplate = `{
             "description": "Information that should be available when you add a course",
             "type": "object",
             "required": [
-                "abbreviation",
                 "email",
-                "lecturer",
                 "name"
             ],
             "properties": {
@@ -2090,12 +2790,8 @@ const docTemplate = `{
                     "type": "string",
                     "example": "someone@example.com"
                 },
-                "id": {
-                    "description": "Course ID, Provided by query",
-                    "type": "string"
-                },
                 "lecturer": {
-                    "description": "Course Lecturer",
+                    "description": "Course Lecturer Name",
                     "type": "string"
                 },
                 "majabbr": {
@@ -2150,10 +2846,6 @@ const docTemplate = `{
                     "description": "Faculty Name Abbreviation",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Faculty ID, Provided by Query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Faculty Name",
                     "type": "string"
@@ -2164,6 +2856,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",
@@ -2248,10 +3002,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"
@@ -2282,11 +3032,15 @@ const docTemplate = `{
         "material.CreateMaterialRequest": {
             "type": "object",
             "required": [
-                "name"
+                "name",
+                "week"
             ],
             "properties": {
                 "name": {
                     "type": "string"
+                },
+                "week": {
+                    "type": "integer"
                 }
             }
         },
@@ -2359,6 +3113,90 @@ 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.AddQuizRequestPayload": {
+            "description": "Information that should be available when you add a quiz",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name"
+            ],
+            "properties": {
+                "addQuizToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Quiz Name",
+                    "type": "string"
+                }
+            }
+        },
         "quiz.AnswerOption": {
             "type": "object",
             "properties": {
@@ -2487,6 +3325,20 @@ const docTemplate = `{
                 }
             }
         },
+        "quiz.UpdateQuizRequestPayload": {
+            "description": "Information that should be available when you update a quiz",
+            "type": "object",
+            "properties": {
+                "id": {
+                    "description": "Quiz ID, Set by param",
+                    "type": "string"
+                },
+                "updateQuizToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "refresh.RefreshResponsePayload": {
             "description": "Refresh endpoint response when process success",
             "type": "object",
diff --git a/docs/swagger.json b/docs/swagger.json
index 883d3d799d994fab91eb3dbf9e1aee4d8483c36f..ce06490cd179815074f2a344dc3bddfa5b7a454e 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",
@@ -1523,9 +2057,210 @@
                         }
                     }
                 }
-            },
-            "post": {
-                "description": "Add content of 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
+                    },
+                    {
+                        "description": "Add Quiz payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.AddQuizRequestPayload"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/web.BaseResponse"
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz/{id}": {
+            "get": {
+                "description": "Get Quiz Detail",
                 "consumes": [
                     "application/json"
                 ],
@@ -1533,30 +2268,14 @@
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Add Content",
+                "summary": "Get Quiz Detail",
                 "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",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1574,29 +2293,17 @@
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "$ref": "#/definitions/material.NewContentResponse"
+                                            "$ref": "#/definitions/quiz.Quiz"
                                         }
                                     }
                                 }
                             ]
                         }
-                    },
-                    "400": {
-                        "description": "Bad Request",
-                        "schema": {
-                            "$ref": "#/definitions/web.BaseResponse"
-                        }
-                    },
-                    "401": {
-                        "description": "Unauthorized",
-                        "schema": {
-                            "$ref": "#/definitions/web.BaseResponse"
-                        }
                     }
                 }
             },
             "delete": {
-                "description": "Delete material",
+                "description": "Delete Quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1604,21 +2311,14 @@
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Delete material",
+                "summary": "Delete Quiz",
                 "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Access token",
-                        "name": "Authorization",
-                        "in": "header",
-                        "required": true
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
-                        "description": "Material id",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
@@ -1632,11 +2332,9 @@
                         }
                     }
                 }
-            }
-        },
-        "/material/{id}/content/{content-id}": {
-            "delete": {
-                "description": "Delete content of material",
+            },
+            "patch": {
+                "description": "Update Quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1644,32 +2342,26 @@
                     "application/json"
                 ],
                 "tags": [
-                    "content"
+                    "quiz"
                 ],
-                "summary": "Delete Content",
+                "summary": "Update Quiz",
                 "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Access token",
-                        "name": "Authorization",
-                        "in": "header",
-                        "required": true
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
-                        "description": "Material id",
+                        "description": "Quiz id",
                         "name": "id",
                         "in": "path",
                         "required": true
                     },
                     {
-                        "type": "string",
-                        "format": "uuid",
-                        "description": "Content id",
-                        "name": "content-id",
-                        "in": "path",
-                        "required": true
+                        "description": "Update Quiz payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.UpdateQuizRequestPayload"
+                        }
                     }
                 ],
                 "responses": {
@@ -1682,9 +2374,9 @@
                 }
             }
         },
-        "/quiz/{id}": {
-            "get": {
-                "description": "Get Quiz Detail",
+        "/quiz/{id}/finish": {
+            "post": {
+                "description": "Finish quiz session and get the score",
                 "consumes": [
                     "application/json"
                 ],
@@ -1694,8 +2386,24 @@
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Get Quiz Detail",
+                "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",
@@ -1717,7 +2425,7 @@
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "$ref": "#/definitions/quiz.Quiz"
+                                            "$ref": "#/definitions/quiz.QuizDetail"
                                         }
                                     }
                                 }
@@ -1781,7 +2489,7 @@
         },
         "/quiz/{id}/take": {
             "post": {
-                "description": "Finish quiz session and get the score",
+                "description": "Take a quiz",
                 "consumes": [
                     "application/json"
                 ],
@@ -1791,7 +2499,7 @@
                 "tags": [
                     "quiz"
                 ],
-                "summary": "Finish Quiz",
+                "summary": "Take Quiz",
                 "parameters": [
                     {
                         "type": "string",
@@ -1800,15 +2508,6 @@
                         "in": "header",
                         "required": true
                     },
-                    {
-                        "description": "Quiz Finish payload",
-                        "name": "data",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "$ref": "#/definitions/quiz.FinishQuizPayload"
-                        }
-                    },
                     {
                         "type": "string",
                         "format": "uuid",
@@ -2018,7 +2717,6 @@
             "description": "Information that should be available when you add a course",
             "type": "object",
             "required": [
-                "abbreviation",
                 "email",
                 "id",
                 "name"
@@ -2045,6 +2743,10 @@
                     "description": "Course ID",
                     "type": "string"
                 },
+                "lecturer": {
+                    "description": "Course Lecturer Name",
+                    "type": "string"
+                },
                 "majabbr": {
                     "description": "Course Major Abbreviation",
                     "type": "string"
@@ -2063,9 +2765,7 @@
             "description": "Information that should be available when you add a course",
             "type": "object",
             "required": [
-                "abbreviation",
                 "email",
-                "lecturer",
                 "name"
             ],
             "properties": {
@@ -2082,12 +2782,8 @@
                     "type": "string",
                     "example": "someone@example.com"
                 },
-                "id": {
-                    "description": "Course ID, Provided by query",
-                    "type": "string"
-                },
                 "lecturer": {
-                    "description": "Course Lecturer",
+                    "description": "Course Lecturer Name",
                     "type": "string"
                 },
                 "majabbr": {
@@ -2142,10 +2838,6 @@
                     "description": "Faculty Name Abbreviation",
                     "type": "string"
                 },
-                "id": {
-                    "description": "Faculty ID, Provided by Query",
-                    "type": "string"
-                },
                 "name": {
                     "description": "Faculty Name",
                     "type": "string"
@@ -2156,6 +2848,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",
@@ -2240,10 +2994,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"
@@ -2274,11 +3024,15 @@
         "material.CreateMaterialRequest": {
             "type": "object",
             "required": [
-                "name"
+                "name",
+                "week"
             ],
             "properties": {
                 "name": {
                     "type": "string"
+                },
+                "week": {
+                    "type": "integer"
                 }
             }
         },
@@ -2351,6 +3105,90 @@
                 }
             }
         },
+        "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.AddQuizRequestPayload": {
+            "description": "Information that should be available when you add a quiz",
+            "type": "object",
+            "required": [
+                "course_id",
+                "name"
+            ],
+            "properties": {
+                "addQuizToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                },
+                "course_id": {
+                    "description": "Course ID",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "Quiz Name",
+                    "type": "string"
+                }
+            }
+        },
         "quiz.AnswerOption": {
             "type": "object",
             "properties": {
@@ -2479,6 +3317,20 @@
                 }
             }
         },
+        "quiz.UpdateQuizRequestPayload": {
+            "description": "Information that should be available when you update a quiz",
+            "type": "object",
+            "properties": {
+                "id": {
+                    "description": "Quiz ID, Set by param",
+                    "type": "string"
+                },
+                "updateQuizToken": {
+                    "description": "Web Token that was appended to the link",
+                    "type": "string"
+                }
+            }
+        },
         "refresh.RefreshResponsePayload": {
             "description": "Refresh endpoint response when process success",
             "type": "object",
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 58ea9348fb473426c5890cff161bd98360f62bf0..56b3a2e0d692c706ebedfbf508561859fb68dee3 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -75,6 +75,9 @@ definitions:
       id:
         description: Course ID
         type: string
+      lecturer:
+        description: Course Lecturer Name
+        type: string
       majabbr:
         description: Course Major Abbreviation
         type: string
@@ -85,7 +88,6 @@ definitions:
         description: Course Name
         type: string
     required:
-    - abbreviation
     - email
     - id
     - name
@@ -103,11 +105,8 @@ definitions:
         description: Contributor Email
         example: someone@example.com
         type: string
-      id:
-        description: Course ID, Provided by query
-        type: string
       lecturer:
-        description: Course Lecturer
+        description: Course Lecturer Name
         type: string
       majabbr:
         description: Course Major Abbreviation
@@ -122,9 +121,7 @@ definitions:
         description: Web Token that was appended to the link
         type: string
     required:
-    - abbreviation
     - email
-    - lecturer
     - name
     type: object
   faculty.AddFacultyRequestPayload:
@@ -149,9 +146,6 @@ definitions:
       abbreviation:
         description: Faculty Name Abbreviation
         type: string
-      id:
-        description: Faculty ID, Provided by Query
-        type: string
       name:
         description: Faculty Name
         type: string
@@ -162,6 +156,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:
@@ -221,9 +261,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
@@ -249,8 +286,11 @@ definitions:
     properties:
       name:
         type: string
+      week:
+        type: integer
     required:
     - name
+    - week
     type: object
   material.CreateMaterialResponse:
     properties:
@@ -298,6 +338,68 @@ 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.AddQuizRequestPayload:
+    description: Information that should be available when you add a quiz
+    properties:
+      addQuizToken:
+        description: Web Token that was appended to the link
+        type: string
+      course_id:
+        description: Course ID
+        type: string
+      name:
+        description: Quiz Name
+        type: string
+    required:
+    - course_id
+    - name
+    type: object
   quiz.AnswerOption:
     properties:
       answer:
@@ -381,6 +483,16 @@ definitions:
       problem_id:
         type: string
     type: object
+  quiz.UpdateQuizRequestPayload:
+    description: Information that should be available when you update a quiz
+    properties:
+      id:
+        description: Quiz ID, Set by param
+        type: string
+      updateQuizToken:
+        description: Web Token that was appended to the link
+        type: string
+    type: object
   refresh.RefreshResponsePayload:
     description: Refresh endpoint response when process success
     properties:
@@ -1417,6 +1529,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:
@@ -1548,7 +2015,56 @@ paths:
       summary: Delete Content
       tags:
       - content
+  /quiz:
+    put:
+      consumes:
+      - application/json
+      description: New Quiz
+      parameters:
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: Add Quiz payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/quiz.AddQuizRequestPayload'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: New Quiz
+      tags:
+      - quiz
   /quiz/{id}:
+    delete:
+      consumes:
+      - application/json
+      description: Delete Quiz
+      parameters:
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Delete Quiz
+      tags:
+      - quiz
     get:
       consumes:
       - application/json
@@ -1575,6 +2091,71 @@ paths:
       summary: Get Quiz Detail
       tags:
       - quiz
+    patch:
+      consumes:
+      - application/json
+      description: Update Quiz
+      parameters:
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: Update Quiz payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/quiz.UpdateQuizRequestPayload'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/web.BaseResponse'
+      summary: Update Quiz
+      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:
@@ -1611,19 +2192,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
@@ -1642,7 +2217,7 @@ paths:
                 data:
                   $ref: '#/definitions/quiz.QuizDetail'
               type: object
-      summary: Finish Quiz
+      summary: Take Quiz
       tags:
       - quiz
   /reset/confirm:
diff --git a/handler/course/updateCourse.go b/handler/course/updateCourse.go
index 4e2ded686a6281dd2e6baebd5b8868fdcf92c150..597bc92d4c8e3e20b43a008b94aea420a883f2e9 100644
--- a/handler/course/updateCourse.go
+++ b/handler/course/updateCourse.go
@@ -30,6 +30,7 @@ import (
 //	@Router			/course/{id} [patch]
 func (c CourseHandlerImpl) UpdateCourse(w http.ResponseWriter, r *http.Request) {
 	payload := course.UpdateCourseRequestPayload{}
+	payload.ID = chi.URLParam(r, "id")
 	validate := validator.New()
 
 	// Validate payload
@@ -82,7 +83,6 @@ func (c CourseHandlerImpl) UpdateCourse(w http.ResponseWriter, r *http.Request)
 	}
 
 	payload.UpdateCourseToken = token[1]
-	payload.ID = chi.URLParam(r, "id")
 	err := c.CourseService.UpdateCourse(payload)
 
 	if err != nil {
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/material/create_material.go b/handler/material/create_material.go
index 55565566908a318265a647ba142e3047d875a003..d0c0e83768c76dbb309ade648ad685ab9c09605b 100644
--- a/handler/material/create_material.go
+++ b/handler/material/create_material.go
@@ -82,6 +82,7 @@ func (m MaterialHandlerImpl) CreateMaterial(w http.ResponseWriter, r *http.Reque
 		courseId,
 		user.Email,
 		payload.Name,
+		payload.Week,
 	)
 
 	if err != nil {
diff --git a/handler/quiz/delete.go b/handler/quiz/delete.go
new file mode 100644
index 0000000000000000000000000000000000000000..642e1661fa478b38a3b591b74c616acd0e4d6b26
--- /dev/null
+++ b/handler/quiz/delete.go
@@ -0,0 +1,86 @@
+package quiz
+
+import (
+	"net/http"
+	"strings"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/quiz"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+)
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Delete Quiz
+//	@Description	Delete Quiz
+//	@Produce			json
+//	@Accept				json
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Success			200	{object}	web.BaseResponse
+//	@Router				/quiz/{id} [delete]
+func (m QuizHandlerImpl) DeleteQuiz(w http.ResponseWriter, r *http.Request) {
+	payload := quiz.DeleteRequestPayload{}
+	quizId := chi.URLParam(r, "id")
+
+	if quizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	id, err := uuid.Parse(quizId)
+
+	if err != nil {
+		// invalid uuid
+		payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.DeleteToken = token[1]
+	payload.ID = id
+
+	err = m.QuizService.DeleteQuiz(payload)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(nil)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+
+}
\ No newline at end of file
diff --git a/handler/quiz/get.go b/handler/quiz/get.go
index 799ca822a991240a0c6febccb29640720f1b5e67..45918bc40487c4c9c1cdaa091c5a90052e8c8bfb 100644
--- a/handler/quiz/get.go
+++ b/handler/quiz/get.go
@@ -2,10 +2,12 @@ package quiz
 
 import (
 	"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/quiz"
 )
 
 // Index godoc
@@ -55,3 +57,77 @@ func (m QuizHandlerImpl) GetQuizDetail(w http.ResponseWriter, r *http.Request) {
 	m.HttpUtil.WriteSuccessJson(w, responsePayload)
 
 }
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Get Quiz Link
+//	@Description	Get Quiz Link
+//	@Produce			json
+//	@Accept				json
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Success			200	{object}	web.BaseResponse
+//	@Router				/quiz/link/{id} [get]
+
+func (m QuizHandlerImpl) GetQuizLink(w http.ResponseWriter, r *http.Request) {
+	payload := quiz.GetRequestPayload{}
+	quizId := chi.URLParam(r, "id")
+
+	if quizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	id, err := uuid.Parse(quizId)
+
+	if err != nil {
+		// invalid uuid
+		payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+	
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.GetToken = token[1]
+	payload.ID = id
+	response, err := m.QuizService.GetQuizLink(payload)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(response)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
diff --git a/handler/quiz/management.go b/handler/quiz/management.go
new file mode 100644
index 0000000000000000000000000000000000000000..c53a7312c94af88b20b73d4d32a1bd3be8c9ac99
--- /dev/null
+++ b/handler/quiz/management.go
@@ -0,0 +1,171 @@
+package quiz
+
+import (
+	"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/quiz"
+)
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			New Quiz
+//	@Description	New Quiz
+//	@Produce			json
+//	@Accept				json
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Param			    data body quiz.AddQuizRequestPayload true "Add Quiz payload"
+//	@Success			200	{object}	web.BaseResponse
+//	@Router				/quiz [put]
+func (m QuizHandlerImpl) NewQuiz(w http.ResponseWriter, r *http.Request) {
+	payload := quiz.AddQuizRequestPayload{}
+
+	// Validate payload
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := m.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := m.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		m.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	validate := validator.New()
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := m.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.AddQuizToken = token[1]
+
+	response, err := m.QuizService.NewQuiz(payload)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(response)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Update Quiz
+//	@Description	Update Quiz
+//	@Produce			json
+//	@Accept				json
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Param			    data body quiz.UpdateQuizRequestPayload true "Update Quiz payload"
+//	@Success			200	{object}	web.BaseResponse
+//	@Router				/quiz/{id} [patch]
+func (m QuizHandlerImpl) UpdateQuiz(w http.ResponseWriter, r *http.Request) {
+	payload := quiz.UpdateQuizRequestPayload{}
+	quizId := chi.URLParam(r, "id")
+
+	if quizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	id, err := uuid.Parse(quizId)
+
+	if err != nil {
+		// invalid uuid
+		payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+	
+	// Confirm Valid Website Token
+	validateTokenHeader := r.Header.Get("Authorization")
+
+	if validateTokenHeader == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("token is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+		return
+	}
+
+	token := strings.Split(validateTokenHeader, " ")
+
+	if len(token) != 2 {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	if token[0] != "Bearer" {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid token", nil)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+
+	payload.UpdateQuizToken = token[1]
+	payload.ID = id
+	response, err := m.QuizService.UpdateQuiz(payload)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(response)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
diff --git a/handler/quiz/take.go b/handler/quiz/take.go
index 530f4f77823001b1a5027b76d610b8c9ccafcaad..553c6ab6377efbf9ce218a5bd0e9fac1a2d9bc62 100644
--- a/handler/quiz/take.go
+++ b/handler/quiz/take.go
@@ -104,7 +104,7 @@ func (m QuizHandlerImpl) GetQuizSolution(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	detail, err := m.GetSolutionQuiz(r.Context(), quizId, user.Email)
+	detail, err := m.GetSolutionQuiz(r.Context(), quizId, user)
 
 	if err != nil {
 		respErr, ok := err.(web.ResponseError)
@@ -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/handler/quiz/type.go b/handler/quiz/type.go
index 8c3bf6f5567cf7f04be9e42b67558279a0f6159d..4d0e1dc6c900d3d431a1e686de459047b1da188f 100644
--- a/handler/quiz/type.go
+++ b/handler/quiz/type.go
@@ -9,4 +9,8 @@ type QuizHandler interface {
 	TakeQuiz(w http.ResponseWriter, r *http.Request)
 	GetQuizSolution(w http.ResponseWriter, r *http.Request)
 	FinishQuiz(w http.ResponseWriter, r *http.Request)
+	NewQuiz(w http.ResponseWriter, r *http.Request)
+	GetQuizLink(w http.ResponseWriter, r *http.Request)
+	UpdateQuiz(w http.ResponseWriter, r *http.Request)
+	DeleteQuiz(w http.ResponseWriter, r *http.Request)
 }
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..9267a5f25f5d83b303ddc548547a0cf6c8c8cfc4 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:"-"`
 
 	// 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..497db3bfb12e13762480c7a0df312f98f7d32875 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:"-"`
 
 	// Major Name
 	Name string `json:"name" validate:"required"`
diff --git a/model/web/course/request.go b/model/web/course/request.go
index 0fad2befd53b36b1722fa4d295123606277841e3..e1f84ca34394ce1fadf7f0c45a4f35cf3dbc8724 100644
--- a/model/web/course/request.go
+++ b/model/web/course/request.go
@@ -27,7 +27,10 @@ type AddCourseRequestPayload struct {
 	Email string `json:"email" validate:"required,email" example:"someone@example.com"`
 
 	// Course Name Abbreviation
-	Abbreviation string `json:"abbreviation" validate:"required"`
+	Abbreviation string `json:"abbreviation"`
+
+	// Course Lecturer Name
+	Lecturer string `json:"lecturer"`
 }
 
 // DeleteCourse Request Payload
@@ -37,22 +40,21 @@ type DeleteByStringRequestPayload struct {
 	DeleteCourseToken string
 
 	// Course ID, provided by query
-	ID string
+	ID string `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
+	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 +64,7 @@ type UpdateCourseRequestPayload struct {
 	UpdateCourseToken string
 
 	// Course ID, Provided by query
-	ID string `json:"id"`
+	ID string `json:"-"`
 
 	// Course Name
 	Name string `json:"name" validate:"required"`
@@ -80,10 +82,8 @@ type UpdateCourseRequestPayload struct {
 	Email string `json:"email" validate:"required,email" example:"someone@example.com"`
 
 	// Course Name Abbreviation
-	Abbreviation string `json:"abbreviation" validate:"required"`
+	Abbreviation string `json:"abbreviation"`
 
-	// Course Lecturer
-	Lecturer string `json:"lecturer" validate:"required"`
+	// Course Lecturer Name
+	Lecturer string `json:"lecturer"`
 }
-
-
diff --git a/model/web/error_code.go b/model/web/error_code.go
index 9b29b2d14e9caac4d013f7474592e25ff70b66d5..f150f3f1bf7d5211713144d3c5bfaaac3a11c618 100644
--- a/model/web/error_code.go
+++ b/model/web/error_code.go
@@ -12,7 +12,10 @@ const (
 	FacultyNotExist    string = "FACULTY_NOT_EXIST"
 	MajorNotExist      string = "MAJOR_NOT_EXIST"
 	CourseNotExist     string = "COURSE_NOT_EXIST"
+	LessonNotExist     string = "LESSON_NOT_EXIST"
+	LessonMaterialNotExist string = "LESSON_MATERIAL_NOT_EXIST"
 	IDExists           string = "ID_ALREADY_EXISTS"
+	NotExist           string = "NOT_EXIST"
 
 	TokenError string = "TOKEN_ERROR"
 )
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/model/web/material/material.go b/model/web/material/material.go
index 98f8c6cdae84025cf0079c2df683a3be1767420b..84da097087fd4201689587c35d8f0e962865eca5 100644
--- a/model/web/material/material.go
+++ b/model/web/material/material.go
@@ -4,6 +4,7 @@ import "github.com/google/uuid"
 
 type CreateMaterialRequest struct {
 	Name string `json:"name" validate:"required"`
+	Week int    `json:"week" validate:"required"`
 }
 
 type CreateMaterialResponse struct {
diff --git a/model/web/quiz/request.go b/model/web/quiz/request.go
new file mode 100644
index 0000000000000000000000000000000000000000..634967c6121796140dae0868916e93ca6439edbc
--- /dev/null
+++ b/model/web/quiz/request.go
@@ -0,0 +1,66 @@
+package quiz
+
+import (
+	"github.com/google/uuid"
+)
+
+// AddQuiz Request Payload
+//
+//	@Description	Information that should be available when you add a quiz
+type AddQuizRequestPayload struct {
+	// Web Token that was appended to the link
+	AddQuizToken string
+
+	// Quiz Name
+	Name string `json:"name" validate:"required"`
+
+	// Course ID
+	CourseID string `json:"course_id" validate:"required"`
+}
+
+// UpdateQuiz Request Payload
+//
+//	@Description	Information that should be available when you update a quiz
+type UpdateQuizRequestPayload struct {
+	// Web Token that was appended to the link
+	UpdateQuizToken string
+
+	// Quiz ID, Set by param
+	ID uuid.UUID `json:"id"`
+}
+
+// DeleteQuiz Request Payload
+//
+//	@Description	Information that should be available when you delete using uuid
+type DeleteRequestPayload struct {
+	// Web Token that was appended to the link
+	DeleteToken string
+
+	// Quiz ID, Set by param
+	ID uuid.UUID
+}
+
+// GetUUID Request Payload
+//
+//	@Description	Information that should be available when you get using uuid
+type GetRequestPayload struct {
+	// Web Token that was appended to the link
+	GetToken string
+
+	// Quiz/Problem/Answer ID, provided by query
+	ID uuid.UUID
+}
+
+// Link Response Payload
+//
+//	@Description	Information that you will get upon successful add/update request
+type LinkResponse struct {
+	UploadLink string `json:"upload_link"`
+}
+
+// Path Response Payload
+//
+//	@Description	Information that you will get upon successful get request
+type PathResponse struct {
+	Path string `json:"path"`
+}
\ No newline at end of file
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/material/material.go b/repository/material/material.go
index 87cbd435c379d505d4be048f8d1d5e878ffba019..3618779997d7381591c1c6f679b40885a8020dc6 100644
--- a/repository/material/material.go
+++ b/repository/material/material.go
@@ -35,16 +35,17 @@ func (m MaterialRepositoryImpl) IsUserContributor(id uuid.UUID, email string) (b
 	return true, nil
 }
 
-func (m MaterialRepositoryImpl) New(courseId string, creatorEmail string, name string) (uuid.UUID, error) {
-	return m.NewWithTransaction(m.builder.Build(), courseId, creatorEmail, name)
+func (m MaterialRepositoryImpl) New(courseId string, creatorEmail string, name string, week int) (uuid.UUID, error) {
+	return m.NewWithTransaction(m.builder.Build(), courseId, creatorEmail, name, week)
 }
 
-func (m MaterialRepositoryImpl) NewWithTransaction(tx transaction.Transaction, courseId string, creatorEmail string, name string) (uuid.UUID, error) {
+func (m MaterialRepositoryImpl) NewWithTransaction(tx transaction.Transaction, courseId string, creatorEmail string, name string, week int) (uuid.UUID, error) {
 	materialData := &material.Material{
 		ID:           uuid.New(),
 		CourseId:     courseId,
 		CreatorEmail: creatorEmail,
 		Name:         name,
+		Week:         week,
 	}
 
 	err := tx.GetTransaction().Create(materialData).Error
diff --git a/repository/material/type.go b/repository/material/type.go
index 4014763d006c08c2eabeb294a8f043ae023d0b17..6e8ddc93441a80c7b16a52cf756a1e75a0cc5b52 100644
--- a/repository/material/type.go
+++ b/repository/material/type.go
@@ -7,14 +7,14 @@ import (
 )
 
 type MaterialRepository interface {
-	New(courseId string, creatorEmail string, name string) (uuid.UUID, error)
+	New(courseId string, creatorEmail string, name string, week int) (uuid.UUID, error)
 	Delete(id uuid.UUID) error
 	Get(materialId uuid.UUID) (*material.Material, error)
 	GetAll(courseId string) ([]material.Material, error)
 
 	IsUserContributor(id uuid.UUID, email string) (bool, error)
 
-	NewWithTransaction(tx transaction.Transaction, courseId string, creatorEmail string, name string) (uuid.UUID, error)
+	NewWithTransaction(tx transaction.Transaction, courseId string, creatorEmail string, name string, week int) (uuid.UUID, error)
 	DeleteWithTransaction(tx transaction.Transaction, id uuid.UUID) error
 	GetAllWithTransaction(tx transaction.Transaction, courseId string) ([]material.Material, error)
 }
diff --git a/repository/quiz/impl.go b/repository/quiz/impl.go
index e51495422f1a10911dd47bf00b1764eb541446ab..fdefa4688f0ce895e0f115a42e1f795c38a57672 100644
--- a/repository/quiz/impl.go
+++ b/repository/quiz/impl.go
@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/course"
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/model/web"
 	"gitlab.informatika.org/ocw/ocw-backend/provider/db"
@@ -39,12 +40,20 @@ func (q *QuizRepositoryImpl) GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error)
 	return result, nil
 }
 
-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
+func (q *QuizRepositoryImpl) UpdateScore(email string, quizId uuid.UUID, score int) error {
+	tx := q.db.Begin()
+	defer tx.Commit()
+
+	tx.Where("quiz_id = ? AND email = ?", quizId, email).Delete(&quiz.QuizTake{})
+
+	return tx.
+		Create(quiz.QuizTake{
+			Score:      score,
+			IsFinished: true,
+			QuizId:     quizId,
+			Email:      email,
+			Id:         uuid.New(),
+		}).Error
 }
 
 func (q *QuizRepositoryImpl) NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error) {
@@ -63,19 +72,52 @@ func (q *QuizRepositoryImpl) NewTake(quizId uuid.UUID, userEmail string) (uuid.U
 	return id, err
 }
 
+func (q *QuizRepositoryImpl) IsUserContributor(id string, email string) (bool, error) {
+	err := q.db.Where("id = ? AND email = ?", id, email).Find(&course.Course{}).Error
+
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+func (q *QuizRepositoryImpl) NewQuiz(quiz quiz.Quiz) error {
+	return q.db.Create(&quiz).Error
+}
+
+func (q *QuizRepositoryImpl) UpdateQuiz(quiz quiz.Quiz) error {
+	return q.db.Save(quiz).Error
+}
+
+func (q *QuizRepositoryImpl) GetQuizLink(quizId uuid.UUID) (string, error) {
+	result := &quiz.Quiz{}
+	err := q.db.Where("id = ?", quizId).First(result).Error
+
+	if errors.Is(err, gorm.ErrRecordNotFound) {
+		return "", web.NewResponseError("Record not found", "ERR_NOT_FOUND")
+	}
+
+	return result.QuizPath, nil
+}
+
+func (q *QuizRepositoryImpl) Delete(quizId uuid.UUID) error {
+	return q.db.Delete(&quiz.Quiz{}, quizId).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) {
@@ -93,5 +135,9 @@ func (q *QuizRepositoryImpl) GetLastTake(quizId uuid.UUID, userEmail string) (*q
 		Where("quiz_id = ? AND email = ?", quizId, userEmail).
 		Last(result).Error
 
+	if errors.Is(err, gorm.ErrRecordNotFound) {
+		return nil, nil
+	}
+
 	return result, err
 }
diff --git a/repository/quiz/type.go b/repository/quiz/type.go
index 1b4e0cbeca391ec136dfc8c696d1c058d49e55e4..362686b7a9cc3295c05f680e074f2920afd94ea3 100644
--- a/repository/quiz/type.go
+++ b/repository/quiz/type.go
@@ -8,8 +8,13 @@ import (
 type QuizRepository interface {
 	GetQuizes(courseId string) ([]quiz.Quiz, error)
 	GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error)
-	UpdateScore(takeId uuid.UUID, score int) error
+	UpdateScore(email string, quizId uuid.UUID, score int) error
 	NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error)
+	IsUserContributor(id string, email string) (bool, error)
+	NewQuiz(quiz quiz.Quiz) error
+	UpdateQuiz(quiz quiz.Quiz) error
+	GetQuizLink(quizId uuid.UUID) (string, error)
+	Delete(quizId uuid.UUID) error
 	IsActiveTake(quizId uuid.UUID, userEmail string) (bool, error)
 	GetAllTake(quizId uuid.UUID, userEmail string) ([]quiz.QuizTake, error)
 	GetLastTake(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/quiz/route.go b/routes/quiz/route.go
index b89269412c9add8ccc39a190a965f187a13c15b9..d75c278d19c5ba6d8b4fa62238f8081342c5e374 100644
--- a/routes/quiz/route.go
+++ b/routes/quiz/route.go
@@ -14,7 +14,6 @@ type QuizRoutes struct {
 
 func (q QuizRoutes) Register(r chi.Router) {
 	r.Get("/course/{id}/quiz", q.QuizHandler.GetAllQuizes)
-	r.Get("/quiz/{id}", q.QuizHandler.GetQuizDetail)
 
 	guard := q.GuardBuilder.Build(
 		user.Student,
@@ -36,4 +35,23 @@ func (q QuizRoutes) Register(r chi.Router) {
 		r.Use(guard)
 		r.Get("/", q.QuizHandler.GetQuizSolution)
 	})
+
+	r.Route("/quiz/{id}", func(r chi.Router) {
+		r.Get("/", q.QuizHandler.GetQuizDetail)
+		r.Route("/", func(r chi.Router) {
+			r.Use(guard)
+			r.Patch("/", q.QuizHandler.UpdateQuiz)
+			r.Delete("/", q.QuizHandler.DeleteQuiz)
+		})
+	})
+	
+	r.Route("/quiz", func(r chi.Router) {
+		r.Use(guard)
+		r.Put("/", q.QuizHandler.NewQuiz)
+	})
+
+	r.Route("/quiz/link/{id}", func(r chi.Router) {
+		r.Use(guard)
+		r.Get("/", q.QuizHandler.GetQuizLink)
+	})
 }
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/admin/addUser.go b/service/admin/addUser.go
index 93e53b0a0cccb8921ec5a00b742c6d1b00df9c93..8bcf120e393053195ff37f83cbf2486afd256745 100644
--- a/service/admin/addUser.go
+++ b/service/admin/addUser.go
@@ -10,11 +10,11 @@ func (as AdminServiceImpl) AddUser(payload req.AdminAddUserPayload) error {
 	var role user.UserRole
 
 	// TODO: move this
-	if (payload.Role == "admin") {
+	if payload.Role == "admin" {
 		role = user.Admin
-	} else if (payload.Role == "contributor") {
+	} else if payload.Role == "contributor" {
 		role = user.Contributor
-	} else if (payload.Role == "member") {
+	} else if payload.Role == "member" {
 		role = user.Student
 	}
 
@@ -26,4 +26,4 @@ func (as AdminServiceImpl) AddUser(payload req.AdminAddUserPayload) error {
 	})
 
 	return err
-}
\ No newline at end of file
+}
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/course/add.go b/service/course/add.go
index a94a59b6e56c8d465adf46559d3877dff50b34e0..bbed9ccc8d3cf5996e5615f92a82e7b45ed62b29 100644
--- a/service/course/add.go
+++ b/service/course/add.go
@@ -61,6 +61,7 @@ func (c CourseServiceImpl) AddCourse(payload course.AddCourseRequestPayload) err
 		Description:  payload.Description,
 		Email:        payload.Email,
 		Abbreviation: payload.Abbreviation,
+		Lecturer:     payload.Lecturer,
 	})
 
 	if err != nil {
diff --git a/service/course/update.go b/service/course/update.go
index 76df6c292d130c3595bbd85a1d0061c1a20ff553..757847e81512f580f8c3ebe192aa4d28e4e574e2 100644
--- a/service/course/update.go
+++ b/service/course/update.go
@@ -7,9 +7,9 @@ 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/course"
 	"gitlab.informatika.org/ocw/ocw-backend/model/web/course/faculty"
 	"gitlab.informatika.org/ocw/ocw-backend/model/web/course/major"
-	"gitlab.informatika.org/ocw/ocw-backend/model/web/course"
 	"gorm.io/gorm"
 )
 
@@ -45,13 +45,13 @@ func (c CourseServiceImpl) UpdateCourse(payload course.UpdateCourseRequestPayloa
 	}
 
 	err = c.CourseRepository.UpdateCourse(domCourse.Course{
-		ID: payload.ID,
-		Name: payload.Name,
-		Major_id: payload.MajorID,
-		Description: payload.Description,
-		Email: payload.Email,
+		ID:           payload.ID,
+		Name:         payload.Name,
+		Major_id:     payload.MajorID,
+		Description:  payload.Description,
+		Email:        payload.Email,
 		Abbreviation: payload.Abbreviation,
-		Lecturer: payload.Lecturer,
+		Lecturer:     payload.Lecturer,
 	})
 
 	if err != nil {
@@ -66,7 +66,7 @@ func (c CourseServiceImpl) UpdateCourse(payload course.UpdateCourseRequestPayloa
 }
 
 func (c CourseServiceImpl) UpdateMajor(payload major.UpdateMajorRequestPayload) error {
-	
+
 	// Validate Role
 	claim, err := c.TokenUtil.Validate(payload.UpdateMajorToken, token.Access)
 
@@ -94,11 +94,11 @@ func (c CourseServiceImpl) UpdateMajor(payload major.UpdateMajorRequestPayload)
 
 		payload.FacultyID = faculty.ID
 	}
-	
+
 	err = c.CourseRepository.UpdateMajor(domCourse.Major{
-		ID: payload.ID,
-		Name: payload.Name,
-		Fac_id: payload.FacultyID,
+		ID:           payload.ID,
+		Name:         payload.Name,
+		Fac_id:       payload.FacultyID,
 		Abbreviation: payload.Abbreviation,
 	})
 
@@ -126,10 +126,10 @@ func (c CourseServiceImpl) UpdateFaculty(payload faculty.UpdateFacultyRequestPay
 	if claim.Role != user.Admin {
 		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
 	}
-	
+
 	err = c.CourseRepository.UpdateFaculty(domCourse.Faculty{
-		ID: payload.ID,
-		Name: payload.Name,
+		ID:           payload.ID,
+		Name:         payload.Name,
 		Abbreviation: payload.Abbreviation,
 	})
 
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/service/material/impl.go b/service/material/impl.go
index c50b67586123fcf70acf3c2c0a4ee7f42b53034c..02a5b425925d957d4d5023cf8e3f1050c83814e5 100644
--- a/service/material/impl.go
+++ b/service/material/impl.go
@@ -32,14 +32,14 @@ func (m MaterialServiceImpl) GetById(materialId uuid.UUID) (*materialDomain.Mate
 	return material, err
 }
 
-func (m MaterialServiceImpl) Create(courseId string, email string, name string) (uuid.UUID, error) {
+func (m MaterialServiceImpl) Create(courseId string, email string, name string, week int) (uuid.UUID, error) {
 	isSuccess := false
 	tx := m.TransactionBuilder.Build()
 
 	tx.Begin()
 	defer tx.Auto(&isSuccess)
 
-	id, err := m.MaterialRepository.NewWithTransaction(tx, courseId, email, name)
+	id, err := m.MaterialRepository.NewWithTransaction(tx, courseId, email, name, week)
 
 	if err != nil {
 		return uuid.Nil, err
diff --git a/service/material/type.go b/service/material/type.go
index ca617ce6fdce82217b439b2f4b1f0a0b58d3545d..9cc1f19497423d3a25cbe4ce0cee8b085b3b5e9e 100644
--- a/service/material/type.go
+++ b/service/material/type.go
@@ -6,7 +6,7 @@ import (
 )
 
 type MaterialService interface {
-	Create(courseId string, email string, name string) (uuid.UUID, error)
+	Create(courseId string, email string, name string, week int) (uuid.UUID, error)
 	Delete(materialId uuid.UUID, email string) error
 	Get(courseId string) ([]material.Material, error)
 	GetById(materialId uuid.UUID) (*material.Material, error)
diff --git a/service/quiz/impl.go b/service/quiz/impl.go
index 3898cd448978c6604f71f68e7561077c9c396a00..12e0377b14e9a922e9fd1b346dc02c39c94f352a 100644
--- a/service/quiz/impl.go
+++ b/service/quiz/impl.go
@@ -4,19 +4,33 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"errors"
+	"fmt"
+	"strings"
 
 	"github.com/google/uuid"
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
+	userDomain "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"
+	model "gitlab.informatika.org/ocw/ocw-backend/model/web/quiz"
 	"gitlab.informatika.org/ocw/ocw-backend/provider/storage"
 	quizRepo "gitlab.informatika.org/ocw/ocw-backend/repository/quiz"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
+	tokenUtil "gitlab.informatika.org/ocw/ocw-backend/utils/token"
+	"gorm.io/gorm"
 )
 
 type QuizServiceImpl struct {
 	quizRepo.QuizRepository
 	storage.Storage
+	tokenUtil.TokenUtil
+	logger.Logger
+	*env.Environment
 }
 
+// TODO: should be for admins, make ones for users which doesnt expose minio link
 func (q QuizServiceImpl) ListAllQuiz(courseId string) ([]quiz.Quiz, error) {
 	return q.QuizRepository.GetQuizes(courseId)
 }
@@ -76,26 +90,30 @@ func (q QuizServiceImpl) DoTakeQuiz(ctx context.Context, quizId uuid.UUID, email
 	return result, nil
 }
 
-func (q QuizServiceImpl) GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error) {
+func (q QuizServiceImpl) GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, user token.UserClaim) (*quiz.QuizDetail, error) {
 	result, err := q.getQuizDetail(ctx, quizId)
 
 	if err != nil {
 		return nil, err
 	}
 
-	_, err = q.GetLastTake(quizId, email)
+	last, err := q.GetLastTake(quizId, user.Email)
 
 	if err != nil {
 		return nil, err
 	}
 
-	taken, err := q.IsActiveTake(quizId, email)
+	if last == nil && user.Role == userDomain.Student {
+		return nil, web.NewResponseError("user is not allow to access this data", "ERR_NOT_ALLOWED")
+	}
+
+	taken, err := q.IsActiveTake(quizId, user.Email)
 
 	if err != nil {
 		return nil, err
 	}
 
-	if taken {
+	if taken && user.Role == userDomain.Student {
 		return nil, web.NewResponseError("user is not allow to access this data", "ERR_NOT_ALLOWED")
 	}
 
@@ -162,7 +180,7 @@ func (q QuizServiceImpl) DoFinishQuiz(ctx context.Context, quizId uuid.UUID, ema
 		return nil, err
 	}
 
-	err = q.QuizRepository.UpdateScore(data.Id, int(score))
+	err = q.QuizRepository.UpdateScore(email, quizId, int(score))
 
 	if err != nil {
 		return nil, err
@@ -170,3 +188,172 @@ func (q QuizServiceImpl) DoFinishQuiz(ctx context.Context, quizId uuid.UUID, ema
 
 	return data, nil
 }
+
+func (q QuizServiceImpl) isQuizContributor(courseId string, email string) error {
+	_, err := q.QuizRepository.IsUserContributor(courseId, email)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return web.NewResponseError("course and user combination not found", "NOT_OWNER")
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+func (q QuizServiceImpl) NewQuiz(payload model.AddQuizRequestPayload) (*model.LinkResponse, error) {
+	// Validate Role
+	claim, err := q.TokenUtil.Validate(payload.AddQuizToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return &model.LinkResponse{}, web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == userDomain.Student {
+		return &model.LinkResponse{}, web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	// Validate Ownership
+	if err := q.isQuizContributor(payload.CourseID, claim.Email); err != nil {
+		return &model.LinkResponse{}, err
+	}
+
+	path := fmt.Sprintf("%s/%s.json", q.BucketQuizBasePath, strings.ReplaceAll(uuid.New().String(), "-", ""))
+	uploadLink, err := q.Storage.CreatePutSignedLink(context.Background(), path)
+
+	if err != nil {
+		q.Logger.Error("Some error happened when generate link")
+		q.Logger.Error(err.Error())
+		return &model.LinkResponse{}, err
+	}
+
+	err = q.QuizRepository.NewQuiz(quiz.Quiz{
+		Id:           uuid.New(),
+		Name:         payload.Name,
+		CourseId:     payload.CourseID,
+		CreatorEmail: claim.Email,
+		QuizPath:     path,
+	})
+
+	if err != nil {
+		q.Logger.Error("Some error happened when insert to repository")
+		q.Logger.Error(err.Error())
+		return &model.LinkResponse{}, err
+	}
+
+	return &model.LinkResponse{UploadLink: uploadLink}, nil
+}
+
+func (q QuizServiceImpl) UpdateQuiz(payload model.UpdateQuizRequestPayload) (*model.LinkResponse, error) {
+	// Validate Role
+	claim, err := q.TokenUtil.Validate(payload.UpdateQuizToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return &model.LinkResponse{}, web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == userDomain.Student {
+		return &model.LinkResponse{}, web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	// Get Quiz Detail
+	prev, err := q.QuizRepository.GetQuizDetail(payload.ID)
+
+	if err != nil {
+		return &model.LinkResponse{}, err
+	}
+
+	// Validate Ownership
+	if err := q.isQuizContributor(prev.CourseId, claim.Email); err != nil {
+		return &model.LinkResponse{}, err
+	}
+
+	path := fmt.Sprintf("%s/%s.json", q.BucketQuizBasePath, strings.ReplaceAll(uuid.New().String(), "-", ""))
+	uploadLink, err := q.Storage.CreatePutSignedLink(context.Background(), path)
+
+	if err != nil {
+		q.Logger.Error("Some error happened when generate link")
+		q.Logger.Error(err.Error())
+		return &model.LinkResponse{}, err
+	}
+
+	err = q.QuizRepository.UpdateQuiz(quiz.Quiz{
+		Id:           prev.Id,
+		Name:         prev.Name,
+		CourseId:     prev.CourseId,
+		CreatorEmail: prev.CreatorEmail,
+		QuizPath:     path,
+	})
+
+	if err != nil {
+		q.Logger.Error("Some error happened when inserting new link")
+		q.Logger.Error(err.Error())
+		return &model.LinkResponse{}, err
+	}
+
+	return &model.LinkResponse{UploadLink: uploadLink}, nil
+}
+
+func (q QuizServiceImpl) GetQuizLink(payload model.GetRequestPayload) (*model.PathResponse, error) {
+	// Validate Role
+	claim, err := q.TokenUtil.Validate(payload.GetToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return &model.PathResponse{}, web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == userDomain.Student {
+		return &model.PathResponse{}, web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	// Get Quiz Detail
+	quiz, err := q.QuizRepository.GetQuizDetail(payload.ID)
+
+	if err != nil {
+		return &model.PathResponse{}, err
+	}
+
+	// Validate Ownership
+	if err := q.isQuizContributor(quiz.CourseId, claim.Email); err != nil {
+		return &model.PathResponse{}, err
+	}
+
+	return &model.PathResponse{Path: quiz.QuizPath}, nil
+}
+
+func (q QuizServiceImpl) DeleteQuiz(payload model.DeleteRequestPayload) error {
+	// Validate Role
+	claim, err := q.TokenUtil.Validate(payload.DeleteToken, token.Access)
+
+	// Invalid Token
+	if err != nil {
+		return web.NewResponseErrorFromError(err, web.TokenError)
+	}
+
+	// Unauthorized Role
+	if claim.Role == userDomain.Student {
+		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+	}
+
+	// Get Quiz Detail
+	quiz, err := q.QuizRepository.GetQuizDetail(payload.ID)
+
+	if err != nil {
+		return err
+	}
+
+	// Validate Ownership
+	if err := q.isQuizContributor(quiz.CourseId, claim.Email); err != nil {
+		return err
+	}
+
+	return q.QuizRepository.Delete(payload.ID)
+}
diff --git a/service/quiz/type.go b/service/quiz/type.go
index 7c97e4965500fb25f75c19a4117c536559fcf9a8..f06407ac5bd9363b170144c46e06ce6fae85f7d0 100644
--- a/service/quiz/type.go
+++ b/service/quiz/type.go
@@ -5,6 +5,8 @@ import (
 
 	"github.com/google/uuid"
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/auth/token"
+	model "gitlab.informatika.org/ocw/ocw-backend/model/web/quiz"
 )
 
 type QuizService interface {
@@ -13,5 +15,10 @@ type QuizService interface {
 
 	DoTakeQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error)
 	DoFinishQuiz(ctx context.Context, quizId uuid.UUID, email string, studentAnswer []quiz.Response) (*quiz.QuizTake, error)
-	GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error)
+	GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, user token.UserClaim) (*quiz.QuizDetail, error)
+	isQuizContributor(courseId string, email string) error
+	NewQuiz(payload model.AddQuizRequestPayload) (*model.LinkResponse, error)
+	UpdateQuiz(payload model.UpdateQuizRequestPayload) (*model.LinkResponse, error)
+	GetQuizLink(payload model.GetRequestPayload) (*model.PathResponse, error)
+	DeleteQuiz(payload model.DeleteRequestPayload) error
 }
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 ff09c00b0ff32c969ddd850d791ca8e35ad8fc9d..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"`
@@ -63,6 +65,7 @@ type Environment struct {
 	BucketSignedGetDuration int64 `env:"BUCKET_SIGNED_GET_DURATION_S" envDefault:"1800"`
 
 	BucketMaterialBasePath string `env:"BUCKET_MATERIAL_BASE_PATH" envDefault:"materials"`
+	BucketQuizBasePath string `env:"BUCKET_MATERIAL_BASE_PATH" envDefault:"quiz"`
 
 	UseBucket bool `env:"USE_BUCKET" envDefault:"true"`
 }