diff --git a/docs/docs.go b/docs/docs.go index b24ad6e..067478f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -713,425 +713,15 @@ const docTemplate = `{ } } }, - "/api/v1/course-management/capstones/{capstoneId}": { + "/api/v1/courses/{courseId}/modules": { "get": { - "description": "Returns one capstone with question-set fields and the ordered question list", "produces": [ "application/json" ], "tags": [ - "course-management" + "modules" ], - "summary": "Get capstone detail", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates capstone content, question-set assessment settings, and optionally replaces the question list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update capstone", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - }, - { - "description": "Update capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateSubModuleCapstoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "delete": { - "description": "Deletes the capstone and its backing question set (and question items)", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Delete capstone", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories": { - "get": { - "description": "Legacy-compatible endpoint for listing course categories", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List course categories", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Legacy-compatible endpoint for creating a course category", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course category", - "parameters": [ - { - "description": "Create category payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseCategoryReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories/{categoryId}/courses": { - "get": { - "description": "Legacy-compatible endpoint that returns courses for one category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List courses by category", - "parameters": [ - { - "type": "integer", - "description": "Category ID", - "name": "categoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories/{categoryId}/sub-categories": { - "get": { - "description": "Returns active sub-categories for the given category ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List sub-categories for a course category", - "parameters": [ - { - "type": "integer", - "description": "Category ID", - "name": "categoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses": { - "get": { - "description": "Returns all courses with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all courses", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Legacy-compatible endpoint for creating a course", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course", - "parameters": [ - { - "description": "Create course payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}": { - "get": { - "description": "Returns one course by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get course detail", + "summary": "List modules for a course", "parameters": [ { "type": "integer", @@ -1139,6 +729,20 @@ const docTemplate = `{ "name": "courseId", "in": "path", "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" } ], "responses": { @@ -1147,29 +751,89 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/domain.Response" } + } + } + }, + "post": { + "description": "Create a module under a course; parent program is taken from the course.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "modules" + ], + "summary": "Create module", + "parameters": [ + { + "type": "integer", + "description": "Course ID", + "name": "courseId", + "in": "path", + "required": true + }, + { + "description": "Module", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateModuleInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } + } + } + } + }, + "/api/v1/courses/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "Get course by ID", + "parameters": [ + { + "type": "integer", + "description": "Course ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } } } }, "put": { - "description": "Legacy-compatible endpoint for updating a course", "consumes": [ "application/json" ], @@ -1177,24 +841,24 @@ const docTemplate = `{ "application/json" ], "tags": [ - "course-management" + "courses" ], "summary": "Update course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true }, { - "description": "Update course payload", + "description": "Fields to update", "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.updateCourseReq" + "$ref": "#/definitions/domain.UpdateCourseInput" } } ], @@ -1205,14 +869,8 @@ const docTemplate = `{ "$ref": "#/definitions/domain.Response" } }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", + "404": { + "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } @@ -1220,19 +878,15 @@ const docTemplate = `{ } }, "delete": { - "description": "Legacy-compatible endpoint for deleting a course", - "produces": [ - "application/json" - ], "tags": [ - "course-management" + "courses" ], "summary": "Delete course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true } @@ -1244,14 +898,8 @@ const docTemplate = `{ "$ref": "#/definitions/domain.Response" } }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", + "404": { + "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } @@ -1259,1765 +907,21 @@ const docTemplate = `{ } } }, - "/api/v1/course-management/courses/{courseId}/hierarchy": { + "/api/v1/courses/{id}/practices": { "get": { - "description": "Returns hierarchy nodes for one course including levels/modules/sub-modules", - "produces": [ - "application/json" - ], "tags": [ - "course-management" + "practices" ], - "summary": "Get hierarchy for a course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/learning-path": { - "get": { - "description": "Legacy-compatible endpoint for course learning path", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get course learning path", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/levels": { - "get": { - "description": "Returns all active levels for one course", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List levels by course", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/thumbnail": { - "post": { - "description": "Legacy-compatible endpoint for updating course thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update course thumbnail", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - }, - { - "description": "Update course thumbnail payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateCourseThumbnailReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/hierarchy": { - "get": { - "description": "Returns full hierarchy: category -\u003e sub-category -\u003e course", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get unified course hierarchy", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/human-language/courses": { - "get": { - "description": "Returns all courses under Human Language category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List Human Language courses", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/human-language/sub-categories": { - "get": { - "description": "Returns active sub-categories under Human Language category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List Human Language sub-categories", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels": { - "get": { - "description": "Returns all levels with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all levels", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a level under a course. cefr_level is a short level code or label (1–64 characters), unique per course; optional title defaults to that value; optional description and thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create level", - "parameters": [ - { - "description": "Create level payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createLevelReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels/{levelId}": { - "get": { - "description": "Returns one level by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get level detail", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates level title, description, thumbnail, display order, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update level", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - }, - { - "description": "Update level payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateLevelReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels/{levelId}/modules": { - "get": { - "description": "Returns all active modules for one level", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List modules by level", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/module-capstones": { - "post": { - "description": "Creates a module-level capstone with a new CAPSTONE question set and ordered questions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create module capstone", - "parameters": [ - { - "description": "Create module capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createModuleCapstoneReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/module-capstones/{moduleCapstoneId}": { - "get": { - "description": "Returns one module capstone with question-set fields and the ordered question list", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get module capstone detail", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates module capstone content, question-set assessment settings, and optionally replaces the question list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update module capstone", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - }, - { - "description": "Update module capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateModuleCapstoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "delete": { - "description": "Deletes the module capstone and its backing question set", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Delete module capstone", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules": { - "get": { - "description": "Returns all modules with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all modules", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a module under a level; optional icon_url stores a module icon image URL", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create module", - "parameters": [ - { - "description": "Create module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createModuleReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}": { - "get": { - "description": "Returns one module by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get module detail", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates module title, description, icon URL, display order, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - }, - { - "description": "Update module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateModuleReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}/capstones": { - "get": { - "description": "Returns active module capstones with question-set settings and question counts", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List capstones under module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}/sub-modules": { - "get": { - "description": "Returns all active sub-modules for one module", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List sub-modules by module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/practices/{practiceId}": { - "get": { - "description": "Returns one active practice by practice ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practice detail", - "parameters": [ - { - "type": "integer", - "description": "Practice ID", - "name": "practiceId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/practices/{practiceId}/detail": { - "get": { - "description": "Returns one active practice with question-set fields and the ordered question list (full item detail)", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practice with full question list", - "parameters": [ - { - "type": "integer", - "description": "Practice ID (sub_module_practices.id)", - "name": "practiceId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-categories": { - "get": { - "description": "Returns all active course sub-categories", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List course sub-categories", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a sub-category under a course category", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course sub-category", - "parameters": [ - { - "description": "Create sub-category payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseSubCategoryReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-categories/{subCategoryId}/courses": { - "get": { - "description": "Returns courses for one sub-category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List courses by sub-category", - "parameters": [ - { - "type": "integer", - "description": "Sub-category ID", - "name": "subCategoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-capstones": { - "post": { - "description": "Creates a capstone assessment with a new CAPSTONE question set, metadata, and ordered questions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create capstone under sub-module", - "parameters": [ - { - "description": "Create capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleCapstoneReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-lessons": { - "post": { - "description": "Creates a sub-module lesson with teaching content (text, image, audio, video URLs) and optional thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create lesson under sub-module", - "parameters": [ - { - "description": "Create lesson payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleLessonReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-lessons/{lessonId}": { - "get": { - "description": "Returns one lesson detail by lesson ID (active or inactive)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get lesson detail", - "parameters": [ - { - "type": "integer", - "description": "Lesson ID", - "name": "lessonId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates lesson teaching content, thumbnail, ordering, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update lesson detail", - "parameters": [ - { - "type": "integer", - "description": "Lesson ID", - "name": "lessonId", - "in": "path", - "required": true - }, - { - "description": "Update lesson payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateSubModuleLessonReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-practices": { - "post": { - "description": "Creates a sub-module practice with metadata and linked question set", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create practice under sub-module", - "parameters": [ - { - "description": "Create practice payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModulePracticeReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-videos": { - "post": { - "description": "Creates a video under a sub-module", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create sub-module video", - "parameters": [ - { - "description": "Create sub-module video payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleVideoReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules": { - "get": { - "description": "Returns all sub-modules with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all sub-modules", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a sub-module under a module; optional thumbnail (image URL) and tips text", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create sub-module", - "parameters": [ - { - "description": "Create sub-module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}": { - "get": { - "description": "Returns one sub-module by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get sub-module detail", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/capstones": { - "get": { - "description": "Returns active capstones for a sub-module with question-set settings and question counts", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List capstones under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/lessons": { - "get": { - "description": "Returns lessons for a sub-module. By default only active lessons; pass include_inactive=true to include inactive rows (e.g. admin / CMS).", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get lessons under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - }, - { - "type": "boolean", - "description": "Include inactive lessons", - "name": "include_inactive", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/practices": { - "get": { - "description": "Returns all active practices attached to a sub-module", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practices under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } + "responses": {} } }, "/api/v1/files/audio": { @@ -3108,123 +1012,6 @@ const docTemplate = `{ } } }, - "/api/v1/internal/db/clear-course-management": { - "post": { - "description": "Truncates course_categories, courses, and sub_courses (same scope as reset-reseed) without re-inserting seed SQL.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "internal" - ], - "summary": "Clear course management hierarchy data only", - "parameters": [ - { - "type": "string", - "description": "Optional token when DB_RESET_RESEED_TOKEN is set", - "name": "X-Seed-Reset-Token", - "in": "header" - }, - { - "description": "Confirmation payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.clearCourseManagementReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/internal/db/reset-reseed": { - "post": { - "description": "Truncates course_categories, courses, and sub_courses. If seed SQL contains INSERTs for those tables (e.g. 007_course_management_seed.sql), they are replayed; otherwise tables are left empty after truncate.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "internal" - ], - "summary": "Reset and reseed database", - "parameters": [ - { - "type": "string", - "description": "Reset token configured in DB_RESET_RESEED_TOKEN", - "name": "X-Seed-Reset-Token", - "in": "header", - "required": true - }, - { - "description": "Confirmation payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.resetAndReseedReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, "/api/v1/internal/users/purge-due-deletions": { "post": { "security": [ @@ -3687,6 +1474,79 @@ const docTemplate = `{ } } }, + "/api/v1/lessons/{id}": { + "get": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + }, + "put": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateLessonInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/lessons/{id}/practices": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/api/v1/logs": { "get": { "description": "Fetches application logs from MongoDB with pagination, level filtering, and search", @@ -3747,6 +1607,148 @@ const docTemplate = `{ } } }, + "/api/v1/modules/{id}": { + "get": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + } + } + }, + "put": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateModuleInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/modules/{id}/practices": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/modules/{moduleId}/lessons": { + "get": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "moduleId", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": {} + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "lessons" + ], + "summary": "Create lesson", + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "moduleId", + "in": "path", + "required": true + }, + { + "description": "Lesson", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateLessonInput" + } + } + ], + "responses": {} + } + }, "/api/v1/notifications/bulk-email": { "post": { "description": "Sends an email to specified user IDs, all users of a role, or direct email addresses with optional image attachment. Optionally schedule for later with scheduled_at (RFC3339).", @@ -4536,6 +2538,84 @@ const docTemplate = `{ } } }, + "/api/v1/practices": { + "post": { + "consumes": [ + "application/json" + ], + "tags": [ + "practices" + ], + "parameters": [ + { + "description": "Practice (parent_kind: COURSE | MODULE | LESSON)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreatePracticeInput" + } + } + ], + "responses": {} + } + }, + "/api/v1/practices/{id}": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + }, + "put": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update (parent is immutable)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdatePracticeInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/api/v1/practices/{practiceId}/questions": { "get": { "description": "Returns paginated questions for a practice(question-set), including AUDIO fields", @@ -4603,6 +2683,304 @@ const docTemplate = `{ } } }, + "/api/v1/programs": { + "get": { + "description": "Paginated list of programs", + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "List programs", + "parameters": [ + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a top-level LMS program", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Create program", + "parameters": [ + { + "description": "Program", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateProgramInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/api/v1/programs/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Get program by ID", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Update program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateProgramInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "programs" + ], + "summary": "Delete program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/api/v1/programs/{id}/courses": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "List courses by program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a course under a program", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "Create course", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Course", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateCourseInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/progress/practices/{id}/complete": { "post": { "description": "Marks a practice question set as completed for the authenticated learner", @@ -4803,53 +3181,6 @@ const docTemplate = `{ } } }, - "/api/v1/question-sets/sub-courses/{subCourseId}/entry-assessment": { - "get": { - "description": "Returns the published INITIAL_ASSESSMENT question set for the given sub-course", - "produces": [ - "application/json" - ], - "tags": [ - "question-sets" - ], - "summary": "Get entry assessment set for a sub-course", - "parameters": [ - { - "type": "integer", - "description": "Sub-course ID", - "name": "subCourseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, "/api/v1/question-sets/{id}": { "get": { "description": "Returns a question set with question count", @@ -9666,6 +7997,121 @@ const docTemplate = `{ "Age55Plus" ] }, + "domain.CreateCourseInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, + "domain.CreateLessonInput": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "description": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "video_url": { + "type": "string" + } + } + }, + "domain.CreateModuleInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "domain.CreatePracticeInput": { + "type": "object", + "required": [ + "parent_id", + "parent_kind", + "question_set_id", + "title" + ], + "properties": { + "parent_id": { + "type": "integer" + }, + "parent_kind": { + "enum": [ + "COURSE", + "MODULE", + "LESSON" + ], + "allOf": [ + { + "$ref": "#/definitions/domain.ParentKind" + } + ] + }, + "persona_id": { + "type": "integer" + }, + "question_set_id": { + "type": "integer" + }, + "quick_tips": { + "type": "string" + }, + "story_description": { + "type": "string" + }, + "story_image": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "domain.CreateProgramInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.CreateRoleReq": { "type": "object", "required": [ @@ -9862,6 +8308,19 @@ const docTemplate = `{ } } }, + "domain.ParentKind": { + "type": "string", + "enum": [ + "COURSE", + "MODULE", + "LESSON" + ], + "x-enum-varnames": [ + "ParentKindCourse", + "ParentKindModule", + "ParentKindLesson" + ] + }, "domain.Permission": { "type": "object", "properties": { @@ -10281,6 +8740,20 @@ const docTemplate = `{ "TeamRoleAnalyst" ] }, + "domain.UpdateCourseInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.UpdateKnowledgeLevelReq": { "type": "object", "properties": { @@ -10293,6 +8766,74 @@ const docTemplate = `{ } } }, + "domain.UpdateLessonInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "video_url": { + "type": "string" + } + } + }, + "domain.UpdateModuleInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "domain.UpdatePracticeInput": { + "type": "object", + "properties": { + "persona_id": { + "type": "integer" + }, + "question_set_id": { + "type": "integer" + }, + "quick_tips": { + "type": "string" + }, + "story_description": { + "type": "string" + }, + "story_image": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "domain.UpdateProgramInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.UpdateRoleReq": { "type": "object", "required": [ @@ -10993,17 +9534,6 @@ const docTemplate = `{ } } }, - "handlers.capstoneQuestionItem": { - "type": "object", - "properties": { - "display_order": { - "type": "integer" - }, - "question_id": { - "type": "integer" - } - } - }, "handlers.changePasswordReq": { "type": "object", "required": [ @@ -11022,71 +9552,6 @@ const docTemplate = `{ } } }, - "handlers.clearCourseManagementReq": { - "type": "object", - "properties": { - "confirm": { - "type": "string" - } - } - }, - "handlers.createCourseCategoryReq": { - "type": "object", - "properties": { - "is_active": { - "type": "boolean" - }, - "name": { - "type": "string" - } - } - }, - "handlers.createCourseReq": { - "type": "object", - "properties": { - "category_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "sub_category_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createCourseSubCategoryReq": { - "type": "object", - "properties": { - "category_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "name": { - "type": "string" - } - } - }, "handlers.createIssueReq": { "type": "object", "required": [ @@ -11110,99 +9575,6 @@ const docTemplate = `{ } } }, - "handlers.createLevelReq": { - "type": "object", - "properties": { - "cefr_level": { - "type": "string" - }, - "course_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "module_id": { - "type": "integer" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "icon_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "level_id": { - "type": "integer" - }, - "title": { - "type": "string" - } - } - }, "handlers.createPlanReq": { "type": "object", "required": [ @@ -11349,9 +9721,6 @@ const docTemplate = `{ "status": { "type": "string" }, - "sub_course_video_id": { - "type": "integer" - }, "time_limit_minutes": { "type": "integer" }, @@ -11360,178 +9729,6 @@ const docTemplate = `{ } } }, - "handlers.createSubModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleLessonReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "sub_module_id": { - "type": "integer" - }, - "teaching_audio_url": { - "type": "string" - }, - "teaching_image_url": { - "type": "string" - }, - "teaching_text": { - "type": "string" - }, - "teaching_video_url": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModulePracticeReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "question_set_id": { - "type": "integer" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleVideoReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "duration": { - "type": "integer" - }, - "instructor_id": { - "type": "string" - }, - "resolution": { - "type": "string" - }, - "status": { - "type": "string" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - }, - "video_url": { - "type": "string" - }, - "visibility": { - "type": "string" - } - } - }, "handlers.initiateDirectPaymentReq": { "type": "object", "required": [ @@ -11691,14 +9888,6 @@ const docTemplate = `{ } } }, - "handlers.resetAndReseedReq": { - "type": "object", - "properties": { - "confirm": { - "type": "string" - } - } - }, "handlers.shortAnswerInput": { "type": "object", "required": [ @@ -11821,34 +10010,6 @@ const docTemplate = `{ } } }, - "handlers.updateCourseReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateCourseThumbnailReq": { - "type": "object", - "properties": { - "thumbnail_url": { - "type": "string" - } - } - }, "handlers.updateIssueStatusReq": { "type": "object", "required": [ @@ -11866,87 +10027,6 @@ const docTemplate = `{ } } }, - "handlers.updateLevelReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "icon_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "title": { - "type": "string" - } - } - }, "handlers.updatePlanReq": { "type": "object", "properties": { @@ -12058,9 +10138,6 @@ const docTemplate = `{ "status": { "type": "string" }, - "sub_course_video_id": { - "type": "integer" - }, "time_limit_minutes": { "type": "integer" }, @@ -12069,82 +10146,6 @@ const docTemplate = `{ } } }, - "handlers.updateSubModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateSubModuleLessonReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "sub_module_id": { - "type": "integer" - }, - "teaching_audio_url": { - "type": "string" - }, - "teaching_image_url": { - "type": "string" - }, - "teaching_text": { - "type": "string" - }, - "teaching_video_url": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, "handlers.verifyOTPReq": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 2841611..6462d0c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -705,425 +705,15 @@ } } }, - "/api/v1/course-management/capstones/{capstoneId}": { + "/api/v1/courses/{courseId}/modules": { "get": { - "description": "Returns one capstone with question-set fields and the ordered question list", "produces": [ "application/json" ], "tags": [ - "course-management" + "modules" ], - "summary": "Get capstone detail", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates capstone content, question-set assessment settings, and optionally replaces the question list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update capstone", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - }, - { - "description": "Update capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateSubModuleCapstoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "delete": { - "description": "Deletes the capstone and its backing question set (and question items)", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Delete capstone", - "parameters": [ - { - "type": "integer", - "description": "Capstone ID", - "name": "capstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories": { - "get": { - "description": "Legacy-compatible endpoint for listing course categories", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List course categories", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Legacy-compatible endpoint for creating a course category", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course category", - "parameters": [ - { - "description": "Create category payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseCategoryReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories/{categoryId}/courses": { - "get": { - "description": "Legacy-compatible endpoint that returns courses for one category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List courses by category", - "parameters": [ - { - "type": "integer", - "description": "Category ID", - "name": "categoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/categories/{categoryId}/sub-categories": { - "get": { - "description": "Returns active sub-categories for the given category ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List sub-categories for a course category", - "parameters": [ - { - "type": "integer", - "description": "Category ID", - "name": "categoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses": { - "get": { - "description": "Returns all courses with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all courses", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Legacy-compatible endpoint for creating a course", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course", - "parameters": [ - { - "description": "Create course payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}": { - "get": { - "description": "Returns one course by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get course detail", + "summary": "List modules for a course", "parameters": [ { "type": "integer", @@ -1131,6 +721,20 @@ "name": "courseId", "in": "path", "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" } ], "responses": { @@ -1139,29 +743,89 @@ "schema": { "$ref": "#/definitions/domain.Response" } + } + } + }, + "post": { + "description": "Create a module under a course; parent program is taken from the course.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "modules" + ], + "summary": "Create module", + "parameters": [ + { + "type": "integer", + "description": "Course ID", + "name": "courseId", + "in": "path", + "required": true + }, + { + "description": "Module", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateModuleInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } + } + } + } + }, + "/api/v1/courses/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "Get course by ID", + "parameters": [ + { + "type": "integer", + "description": "Course ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } } } }, "put": { - "description": "Legacy-compatible endpoint for updating a course", "consumes": [ "application/json" ], @@ -1169,24 +833,24 @@ "application/json" ], "tags": [ - "course-management" + "courses" ], "summary": "Update course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true }, { - "description": "Update course payload", + "description": "Fields to update", "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.updateCourseReq" + "$ref": "#/definitions/domain.UpdateCourseInput" } } ], @@ -1197,14 +861,8 @@ "$ref": "#/definitions/domain.Response" } }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", + "404": { + "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } @@ -1212,19 +870,15 @@ } }, "delete": { - "description": "Legacy-compatible endpoint for deleting a course", - "produces": [ - "application/json" - ], "tags": [ - "course-management" + "courses" ], "summary": "Delete course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true } @@ -1236,14 +890,8 @@ "$ref": "#/definitions/domain.Response" } }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", + "404": { + "description": "Not Found", "schema": { "$ref": "#/definitions/domain.ErrorResponse" } @@ -1251,1765 +899,21 @@ } } }, - "/api/v1/course-management/courses/{courseId}/hierarchy": { + "/api/v1/courses/{id}/practices": { "get": { - "description": "Returns hierarchy nodes for one course including levels/modules/sub-modules", - "produces": [ - "application/json" - ], "tags": [ - "course-management" + "practices" ], - "summary": "Get hierarchy for a course", "parameters": [ { "type": "integer", "description": "Course ID", - "name": "courseId", + "name": "id", "in": "path", "required": true } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/learning-path": { - "get": { - "description": "Legacy-compatible endpoint for course learning path", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get course learning path", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/levels": { - "get": { - "description": "Returns all active levels for one course", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List levels by course", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/courses/{courseId}/thumbnail": { - "post": { - "description": "Legacy-compatible endpoint for updating course thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update course thumbnail", - "parameters": [ - { - "type": "integer", - "description": "Course ID", - "name": "courseId", - "in": "path", - "required": true - }, - { - "description": "Update course thumbnail payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateCourseThumbnailReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/hierarchy": { - "get": { - "description": "Returns full hierarchy: category -\u003e sub-category -\u003e course", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get unified course hierarchy", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/human-language/courses": { - "get": { - "description": "Returns all courses under Human Language category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List Human Language courses", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/human-language/sub-categories": { - "get": { - "description": "Returns active sub-categories under Human Language category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List Human Language sub-categories", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels": { - "get": { - "description": "Returns all levels with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all levels", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a level under a course. cefr_level is a short level code or label (1–64 characters), unique per course; optional title defaults to that value; optional description and thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create level", - "parameters": [ - { - "description": "Create level payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createLevelReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels/{levelId}": { - "get": { - "description": "Returns one level by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get level detail", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates level title, description, thumbnail, display order, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update level", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - }, - { - "description": "Update level payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateLevelReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/levels/{levelId}/modules": { - "get": { - "description": "Returns all active modules for one level", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List modules by level", - "parameters": [ - { - "type": "integer", - "description": "Level ID", - "name": "levelId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/module-capstones": { - "post": { - "description": "Creates a module-level capstone with a new CAPSTONE question set and ordered questions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create module capstone", - "parameters": [ - { - "description": "Create module capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createModuleCapstoneReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/module-capstones/{moduleCapstoneId}": { - "get": { - "description": "Returns one module capstone with question-set fields and the ordered question list", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get module capstone detail", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates module capstone content, question-set assessment settings, and optionally replaces the question list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update module capstone", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - }, - { - "description": "Update module capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateModuleCapstoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "delete": { - "description": "Deletes the module capstone and its backing question set", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Delete module capstone", - "parameters": [ - { - "type": "integer", - "description": "Module capstone ID", - "name": "moduleCapstoneId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules": { - "get": { - "description": "Returns all modules with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all modules", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a module under a level; optional icon_url stores a module icon image URL", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create module", - "parameters": [ - { - "description": "Create module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createModuleReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}": { - "get": { - "description": "Returns one module by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get module detail", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates module title, description, icon URL, display order, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - }, - { - "description": "Update module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateModuleReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}/capstones": { - "get": { - "description": "Returns active module capstones with question-set settings and question counts", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List capstones under module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/modules/{moduleId}/sub-modules": { - "get": { - "description": "Returns all active sub-modules for one module", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List sub-modules by module", - "parameters": [ - { - "type": "integer", - "description": "Module ID", - "name": "moduleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/practices/{practiceId}": { - "get": { - "description": "Returns one active practice by practice ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practice detail", - "parameters": [ - { - "type": "integer", - "description": "Practice ID", - "name": "practiceId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/practices/{practiceId}/detail": { - "get": { - "description": "Returns one active practice with question-set fields and the ordered question list (full item detail)", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practice with full question list", - "parameters": [ - { - "type": "integer", - "description": "Practice ID (sub_module_practices.id)", - "name": "practiceId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-categories": { - "get": { - "description": "Returns all active course sub-categories", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List course sub-categories", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a sub-category under a course category", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create course sub-category", - "parameters": [ - { - "description": "Create sub-category payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createCourseSubCategoryReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-categories/{subCategoryId}/courses": { - "get": { - "description": "Returns courses for one sub-category", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List courses by sub-category", - "parameters": [ - { - "type": "integer", - "description": "Sub-category ID", - "name": "subCategoryId", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-capstones": { - "post": { - "description": "Creates a capstone assessment with a new CAPSTONE question set, metadata, and ordered questions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create capstone under sub-module", - "parameters": [ - { - "description": "Create capstone payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleCapstoneReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-lessons": { - "post": { - "description": "Creates a sub-module lesson with teaching content (text, image, audio, video URLs) and optional thumbnail", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create lesson under sub-module", - "parameters": [ - { - "description": "Create lesson payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleLessonReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-lessons/{lessonId}": { - "get": { - "description": "Returns one lesson detail by lesson ID (active or inactive)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get lesson detail", - "parameters": [ - { - "type": "integer", - "description": "Lesson ID", - "name": "lessonId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "put": { - "description": "Updates lesson teaching content, thumbnail, ordering, and active flag", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Update lesson detail", - "parameters": [ - { - "type": "integer", - "description": "Lesson ID", - "name": "lessonId", - "in": "path", - "required": true - }, - { - "description": "Update lesson payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateSubModuleLessonReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-practices": { - "post": { - "description": "Creates a sub-module practice with metadata and linked question set", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create practice under sub-module", - "parameters": [ - { - "description": "Create practice payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModulePracticeReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-module-videos": { - "post": { - "description": "Creates a video under a sub-module", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create sub-module video", - "parameters": [ - { - "description": "Create sub-module video payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleVideoReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules": { - "get": { - "description": "Returns all sub-modules with pagination", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List all sub-modules", - "parameters": [ - { - "type": "integer", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "Limit", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - }, - "post": { - "description": "Creates a sub-module under a module; optional thumbnail (image URL) and tips text", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Create sub-module", - "parameters": [ - { - "description": "Create sub-module payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.createSubModuleReq" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}": { - "get": { - "description": "Returns one sub-module by ID", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get sub-module detail", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/capstones": { - "get": { - "description": "Returns active capstones for a sub-module with question-set settings and question counts", - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "List capstones under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/lessons": { - "get": { - "description": "Returns lessons for a sub-module. By default only active lessons; pass include_inactive=true to include inactive rows (e.g. admin / CMS).", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get lessons under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - }, - { - "type": "boolean", - "description": "Include inactive lessons", - "name": "include_inactive", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/course-management/sub-modules/{subModuleId}/practices": { - "get": { - "description": "Returns all active practices attached to a sub-module", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "course-management" - ], - "summary": "Get practices under sub-module", - "parameters": [ - { - "type": "integer", - "description": "Sub-module ID", - "name": "subModuleId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } + "responses": {} } }, "/api/v1/files/audio": { @@ -3100,123 +1004,6 @@ } } }, - "/api/v1/internal/db/clear-course-management": { - "post": { - "description": "Truncates course_categories, courses, and sub_courses (same scope as reset-reseed) without re-inserting seed SQL.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "internal" - ], - "summary": "Clear course management hierarchy data only", - "parameters": [ - { - "type": "string", - "description": "Optional token when DB_RESET_RESEED_TOKEN is set", - "name": "X-Seed-Reset-Token", - "in": "header" - }, - { - "description": "Confirmation payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.clearCourseManagementReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, - "/api/v1/internal/db/reset-reseed": { - "post": { - "description": "Truncates course_categories, courses, and sub_courses. If seed SQL contains INSERTs for those tables (e.g. 007_course_management_seed.sql), they are replayed; otherwise tables are left empty after truncate.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "internal" - ], - "summary": "Reset and reseed database", - "parameters": [ - { - "type": "string", - "description": "Reset token configured in DB_RESET_RESEED_TOKEN", - "name": "X-Seed-Reset-Token", - "in": "header", - "required": true - }, - { - "description": "Confirmation payload", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.resetAndReseedReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, "/api/v1/internal/users/purge-due-deletions": { "post": { "security": [ @@ -3679,6 +1466,79 @@ } } }, + "/api/v1/lessons/{id}": { + "get": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + }, + "put": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateLessonInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/lessons/{id}/practices": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Lesson ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/api/v1/logs": { "get": { "description": "Fetches application logs from MongoDB with pagination, level filtering, and search", @@ -3739,6 +1599,148 @@ } } }, + "/api/v1/modules/{id}": { + "get": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + } + } + }, + "put": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateModuleInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "modules" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/modules/{id}/practices": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, + "/api/v1/modules/{moduleId}/lessons": { + "get": { + "tags": [ + "lessons" + ], + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "moduleId", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": {} + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "lessons" + ], + "summary": "Create lesson", + "parameters": [ + { + "type": "integer", + "description": "Module ID", + "name": "moduleId", + "in": "path", + "required": true + }, + { + "description": "Lesson", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateLessonInput" + } + } + ], + "responses": {} + } + }, "/api/v1/notifications/bulk-email": { "post": { "description": "Sends an email to specified user IDs, all users of a role, or direct email addresses with optional image attachment. Optionally schedule for later with scheduled_at (RFC3339).", @@ -4528,6 +2530,84 @@ } } }, + "/api/v1/practices": { + "post": { + "consumes": [ + "application/json" + ], + "tags": [ + "practices" + ], + "parameters": [ + { + "description": "Practice (parent_kind: COURSE | MODULE | LESSON)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreatePracticeInput" + } + } + ], + "responses": {} + } + }, + "/api/v1/practices/{id}": { + "get": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + }, + "put": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update (parent is immutable)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdatePracticeInput" + } + } + ], + "responses": {} + }, + "delete": { + "tags": [ + "practices" + ], + "parameters": [ + { + "type": "integer", + "description": "Practice ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/api/v1/practices/{practiceId}/questions": { "get": { "description": "Returns paginated questions for a practice(question-set), including AUDIO fields", @@ -4595,6 +2675,304 @@ } } }, + "/api/v1/programs": { + "get": { + "description": "Paginated list of programs", + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "List programs", + "parameters": [ + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a top-level LMS program", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Create program", + "parameters": [ + { + "description": "Program", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateProgramInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/api/v1/programs/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Get program by ID", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "programs" + ], + "summary": "Update program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Fields to update", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateProgramInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "programs" + ], + "summary": "Delete program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/api/v1/programs/{id}/courses": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "List courses by program", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "default": 0, + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a course under a program", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "courses" + ], + "summary": "Create course", + "parameters": [ + { + "type": "integer", + "description": "Program ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Course", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateCourseInput" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/domain.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/progress/practices/{id}/complete": { "post": { "description": "Marks a practice question set as completed for the authenticated learner", @@ -4795,53 +3173,6 @@ } } }, - "/api/v1/question-sets/sub-courses/{subCourseId}/entry-assessment": { - "get": { - "description": "Returns the published INITIAL_ASSESSMENT question set for the given sub-course", - "produces": [ - "application/json" - ], - "tags": [ - "question-sets" - ], - "summary": "Get entry assessment set for a sub-course", - "parameters": [ - { - "type": "integer", - "description": "Sub-course ID", - "name": "subCourseId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.Response" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/domain.ErrorResponse" - } - } - } - } - }, "/api/v1/question-sets/{id}": { "get": { "description": "Returns a question set with question count", @@ -9658,6 +7989,121 @@ "Age55Plus" ] }, + "domain.CreateCourseInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, + "domain.CreateLessonInput": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "description": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "video_url": { + "type": "string" + } + } + }, + "domain.CreateModuleInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "domain.CreatePracticeInput": { + "type": "object", + "required": [ + "parent_id", + "parent_kind", + "question_set_id", + "title" + ], + "properties": { + "parent_id": { + "type": "integer" + }, + "parent_kind": { + "enum": [ + "COURSE", + "MODULE", + "LESSON" + ], + "allOf": [ + { + "$ref": "#/definitions/domain.ParentKind" + } + ] + }, + "persona_id": { + "type": "integer" + }, + "question_set_id": { + "type": "integer" + }, + "quick_tips": { + "type": "string" + }, + "story_description": { + "type": "string" + }, + "story_image": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "domain.CreateProgramInput": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.CreateRoleReq": { "type": "object", "required": [ @@ -9854,6 +8300,19 @@ } } }, + "domain.ParentKind": { + "type": "string", + "enum": [ + "COURSE", + "MODULE", + "LESSON" + ], + "x-enum-varnames": [ + "ParentKindCourse", + "ParentKindModule", + "ParentKindLesson" + ] + }, "domain.Permission": { "type": "object", "properties": { @@ -10273,6 +8732,20 @@ "TeamRoleAnalyst" ] }, + "domain.UpdateCourseInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.UpdateKnowledgeLevelReq": { "type": "object", "properties": { @@ -10285,6 +8758,74 @@ } } }, + "domain.UpdateLessonInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "video_url": { + "type": "string" + } + } + }, + "domain.UpdateModuleInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "domain.UpdatePracticeInput": { + "type": "object", + "properties": { + "persona_id": { + "type": "integer" + }, + "question_set_id": { + "type": "integer" + }, + "quick_tips": { + "type": "string" + }, + "story_description": { + "type": "string" + }, + "story_image": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "domain.UpdateProgramInput": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "thumbnail": { + "type": "string" + } + } + }, "domain.UpdateRoleReq": { "type": "object", "required": [ @@ -10985,17 +9526,6 @@ } } }, - "handlers.capstoneQuestionItem": { - "type": "object", - "properties": { - "display_order": { - "type": "integer" - }, - "question_id": { - "type": "integer" - } - } - }, "handlers.changePasswordReq": { "type": "object", "required": [ @@ -11014,71 +9544,6 @@ } } }, - "handlers.clearCourseManagementReq": { - "type": "object", - "properties": { - "confirm": { - "type": "string" - } - } - }, - "handlers.createCourseCategoryReq": { - "type": "object", - "properties": { - "is_active": { - "type": "boolean" - }, - "name": { - "type": "string" - } - } - }, - "handlers.createCourseReq": { - "type": "object", - "properties": { - "category_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "sub_category_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createCourseSubCategoryReq": { - "type": "object", - "properties": { - "category_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "name": { - "type": "string" - } - } - }, "handlers.createIssueReq": { "type": "object", "required": [ @@ -11102,99 +9567,6 @@ } } }, - "handlers.createLevelReq": { - "type": "object", - "properties": { - "cefr_level": { - "type": "string" - }, - "course_id": { - "type": "integer" - }, - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "module_id": { - "type": "integer" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "icon_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "level_id": { - "type": "integer" - }, - "title": { - "type": "string" - } - } - }, "handlers.createPlanReq": { "type": "object", "required": [ @@ -11341,9 +9713,6 @@ "status": { "type": "string" }, - "sub_course_video_id": { - "type": "integer" - }, "time_limit_minutes": { "type": "integer" }, @@ -11352,178 +9721,6 @@ } } }, - "handlers.createSubModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleLessonReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "sub_module_id": { - "type": "integer" - }, - "teaching_audio_url": { - "type": "string" - }, - "teaching_image_url": { - "type": "string" - }, - "teaching_text": { - "type": "string" - }, - "teaching_video_url": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModulePracticeReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "question_set_id": { - "type": "integer" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.createSubModuleVideoReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "duration": { - "type": "integer" - }, - "instructor_id": { - "type": "string" - }, - "resolution": { - "type": "string" - }, - "status": { - "type": "string" - }, - "sub_module_id": { - "type": "integer" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - }, - "video_url": { - "type": "string" - }, - "visibility": { - "type": "string" - } - } - }, "handlers.initiateDirectPaymentReq": { "type": "object", "required": [ @@ -11683,14 +9880,6 @@ } } }, - "handlers.resetAndReseedReq": { - "type": "object", - "properties": { - "confirm": { - "type": "string" - } - } - }, "handlers.shortAnswerInput": { "type": "object", "required": [ @@ -11813,34 +10002,6 @@ } } }, - "handlers.updateCourseReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "intro_video_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateCourseThumbnailReq": { - "type": "object", - "properties": { - "thumbnail_url": { - "type": "string" - } - } - }, "handlers.updateIssueStatusReq": { "type": "object", "required": [ @@ -11858,87 +10019,6 @@ } } }, - "handlers.updateLevelReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateModuleReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "icon_url": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "title": { - "type": "string" - } - } - }, "handlers.updatePlanReq": { "type": "object", "properties": { @@ -12050,9 +10130,6 @@ "status": { "type": "string" }, - "sub_course_video_id": { - "type": "integer" - }, "time_limit_minutes": { "type": "integer" }, @@ -12061,82 +10138,6 @@ } } }, - "handlers.updateSubModuleCapstoneReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "passing_score": { - "type": "integer" - }, - "questions": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.capstoneQuestionItem" - } - }, - "shuffle_questions": { - "type": "boolean" - }, - "status": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "time_limit_minutes": { - "type": "integer" - }, - "tips": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "handlers.updateSubModuleLessonReq": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "display_order": { - "type": "integer" - }, - "is_active": { - "type": "boolean" - }, - "sub_module_id": { - "type": "integer" - }, - "teaching_audio_url": { - "type": "string" - }, - "teaching_image_url": { - "type": "string" - }, - "teaching_text": { - "type": "string" - }, - "teaching_video_url": { - "type": "string" - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, "handlers.verifyOTPReq": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6ab3ed4..f6164f7 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -17,6 +17,81 @@ definitions: - Age35To44 - Age45To54 - Age55Plus + domain.CreateCourseInput: + properties: + description: + type: string + name: + type: string + thumbnail: + type: string + required: + - name + type: object + domain.CreateLessonInput: + properties: + description: + type: string + thumbnail: + type: string + title: + type: string + video_url: + type: string + required: + - title + type: object + domain.CreateModuleInput: + properties: + description: + type: string + icon: + type: string + name: + type: string + required: + - name + type: object + domain.CreatePracticeInput: + properties: + parent_id: + type: integer + parent_kind: + allOf: + - $ref: '#/definitions/domain.ParentKind' + enum: + - COURSE + - MODULE + - LESSON + persona_id: + type: integer + question_set_id: + type: integer + quick_tips: + type: string + story_description: + type: string + story_image: + type: string + title: + type: string + required: + - parent_id + - parent_kind + - question_set_id + - title + type: object + domain.CreateProgramInput: + properties: + description: + type: string + name: + type: string + thumbnail: + type: string + required: + - name + type: object domain.CreateRoleReq: properties: description: @@ -151,6 +226,16 @@ definitions: total_pages: type: integer type: object + domain.ParentKind: + enum: + - COURSE + - MODULE + - LESSON + type: string + x-enum-varnames: + - ParentKindCourse + - ParentKindModule + - ParentKindLesson domain.Permission: properties: created_at: @@ -439,6 +524,15 @@ definitions: - TeamRoleFinance - TeamRoleHR - TeamRoleAnalyst + domain.UpdateCourseInput: + properties: + description: + type: string + name: + type: string + thumbnail: + type: string + type: object domain.UpdateKnowledgeLevelReq: properties: knowledge_level: @@ -447,6 +541,50 @@ definitions: user_id: type: integer type: object + domain.UpdateLessonInput: + properties: + description: + type: string + thumbnail: + type: string + title: + type: string + video_url: + type: string + type: object + domain.UpdateModuleInput: + properties: + description: + type: string + icon: + type: string + name: + type: string + type: object + domain.UpdatePracticeInput: + properties: + persona_id: + type: integer + question_set_id: + type: integer + quick_tips: + type: string + story_description: + type: string + story_image: + type: string + title: + type: string + type: object + domain.UpdateProgramInput: + properties: + description: + type: string + name: + type: string + thumbnail: + type: string + type: object domain.UpdateRoleReq: properties: description: @@ -916,13 +1054,6 @@ definitions: auto_renew: type: boolean type: object - handlers.capstoneQuestionItem: - properties: - display_order: - type: integer - question_id: - type: integer - type: object handlers.changePasswordReq: properties: current_password: @@ -936,48 +1067,6 @@ definitions: - current_password - new_password type: object - handlers.clearCourseManagementReq: - properties: - confirm: - type: string - type: object - handlers.createCourseCategoryReq: - properties: - is_active: - type: boolean - name: - type: string - type: object - handlers.createCourseReq: - properties: - category_id: - type: integer - description: - type: string - intro_video_url: - type: string - is_active: - type: boolean - sub_category_id: - type: integer - thumbnail: - type: string - title: - type: string - type: object - handlers.createCourseSubCategoryReq: - properties: - category_id: - type: integer - description: - type: string - display_order: - type: integer - is_active: - type: boolean - name: - type: string - type: object handlers.createIssueReq: properties: description: @@ -994,67 +1083,6 @@ definitions: - issue_type - subject type: object - handlers.createLevelReq: - properties: - cefr_level: - type: string - course_id: - type: integer - description: - type: string - display_order: - type: integer - is_active: - type: boolean - thumbnail: - type: string - title: - type: string - type: object - handlers.createModuleCapstoneReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - module_id: - type: integer - passing_score: - type: integer - questions: - items: - $ref: '#/definitions/handlers.capstoneQuestionItem' - type: array - shuffle_questions: - type: boolean - status: - type: string - thumbnail: - type: string - time_limit_minutes: - type: integer - tips: - type: string - title: - type: string - type: object - handlers.createModuleReq: - properties: - description: - type: string - display_order: - type: integer - icon_url: - type: string - is_active: - type: boolean - level_id: - type: integer - title: - type: string - type: object handlers.createPlanReq: properties: currency: @@ -1155,8 +1183,6 @@ definitions: type: boolean status: type: string - sub_course_video_id: - type: integer time_limit_minutes: type: integer title: @@ -1165,119 +1191,6 @@ definitions: - set_type - title type: object - handlers.createSubModuleCapstoneReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - passing_score: - type: integer - questions: - items: - $ref: '#/definitions/handlers.capstoneQuestionItem' - type: array - shuffle_questions: - type: boolean - status: - type: string - sub_module_id: - type: integer - thumbnail: - type: string - time_limit_minutes: - type: integer - tips: - type: string - title: - type: string - type: object - handlers.createSubModuleLessonReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - sub_module_id: - type: integer - teaching_audio_url: - type: string - teaching_image_url: - type: string - teaching_text: - type: string - teaching_video_url: - type: string - thumbnail: - type: string - title: - type: string - type: object - handlers.createSubModulePracticeReq: - properties: - description: - type: string - display_order: - type: integer - intro_video_url: - type: string - is_active: - type: boolean - question_set_id: - type: integer - sub_module_id: - type: integer - thumbnail: - type: string - title: - type: string - type: object - handlers.createSubModuleReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - module_id: - type: integer - thumbnail: - type: string - tips: - type: string - title: - type: string - type: object - handlers.createSubModuleVideoReq: - properties: - description: - type: string - display_order: - type: integer - duration: - type: integer - instructor_id: - type: string - resolution: - type: string - status: - type: string - sub_module_id: - type: integer - thumbnail: - type: string - title: - type: string - video_url: - type: string - visibility: - type: string - type: object handlers.initiateDirectPaymentReq: properties: email: @@ -1385,11 +1298,6 @@ definitions: - access_token - refresh_token type: object - handlers.resetAndReseedReq: - properties: - confirm: - type: string - type: object handlers.shortAnswerInput: properties: acceptable_answer: @@ -1473,24 +1381,6 @@ definitions: example: false type: boolean type: object - handlers.updateCourseReq: - properties: - description: - type: string - intro_video_url: - type: string - is_active: - type: boolean - thumbnail: - type: string - title: - type: string - type: object - handlers.updateCourseThumbnailReq: - properties: - thumbnail_url: - type: string - type: object handlers.updateIssueStatusReq: properties: status: @@ -1503,59 +1393,6 @@ definitions: required: - status type: object - handlers.updateLevelReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - thumbnail: - type: string - title: - type: string - type: object - handlers.updateModuleCapstoneReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - passing_score: - type: integer - questions: - items: - $ref: '#/definitions/handlers.capstoneQuestionItem' - type: array - shuffle_questions: - type: boolean - status: - type: string - thumbnail: - type: string - time_limit_minutes: - type: integer - tips: - type: string - title: - type: string - type: object - handlers.updateModuleReq: - properties: - description: - type: string - display_order: - type: integer - icon_url: - type: string - is_active: - type: boolean - title: - type: string - type: object handlers.updatePlanReq: properties: currency: @@ -1629,63 +1466,11 @@ definitions: type: boolean status: type: string - sub_course_video_id: - type: integer time_limit_minutes: type: integer title: type: string type: object - handlers.updateSubModuleCapstoneReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - passing_score: - type: integer - questions: - items: - $ref: '#/definitions/handlers.capstoneQuestionItem' - type: array - shuffle_questions: - type: boolean - status: - type: string - thumbnail: - type: string - time_limit_minutes: - type: integer - tips: - type: string - title: - type: string - type: object - handlers.updateSubModuleLessonReq: - properties: - description: - type: string - display_order: - type: integer - is_active: - type: boolean - sub_module_id: - type: integer - teaching_audio_url: - type: string - teaching_image_url: - type: string - teaching_text: - type: string - teaching_video_url: - type: string - thumbnail: - type: string - title: - type: string - type: object handlers.verifyOTPReq: properties: otp: @@ -2563,43 +2348,24 @@ paths: summary: Refresh token tags: - auth - /api/v1/course-management/capstones/{capstoneId}: - delete: - description: Deletes the capstone and its backing question set (and question - items) - parameters: - - description: Capstone ID - in: path - name: capstoneId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Delete capstone - tags: - - course-management + /api/v1/courses/{courseId}/modules: get: - description: Returns one capstone with question-set fields and the ordered question - list parameters: - - description: Capstone ID + - description: Course ID in: path - name: capstoneId + name: courseId required: true type: integer + - default: 20 + description: Page size + in: query + name: limit + type: integer + - default: 0 + description: Offset + in: query + name: offset + type: integer produces: - application/json responses: @@ -2607,88 +2373,26 @@ paths: description: OK schema: $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get capstone detail + summary: List modules for a course tags: - - course-management - put: - consumes: - - application/json - description: Updates capstone content, question-set assessment settings, and - optionally replaces the question list - parameters: - - description: Capstone ID - in: path - name: capstoneId - required: true - type: integer - - description: Update capstone payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateSubModuleCapstoneReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update capstone - tags: - - course-management - /api/v1/course-management/categories: - get: - description: Legacy-compatible endpoint for listing course categories - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List course categories - tags: - - course-management + - modules post: consumes: - application/json - description: Legacy-compatible endpoint for creating a course category + description: Create a module under a course; parent program is taken from the + course. parameters: - - description: Create category payload + - description: Course ID + in: path + name: courseId + required: true + type: integer + - description: Module in: body name: body required: true schema: - $ref: '#/definitions/handlers.createCourseCategoryReq' + $ref: '#/definitions/domain.CreateModuleInput' produces: - application/json responses: @@ -2700,763 +2404,34 @@ paths: description: Bad Request schema: $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create course category - tags: - - course-management - /api/v1/course-management/categories/{categoryId}/courses: - get: - description: Legacy-compatible endpoint that returns courses for one category - parameters: - - description: Category ID - in: path - name: categoryId - required: true - type: integer - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List courses by category - tags: - - course-management - /api/v1/course-management/categories/{categoryId}/sub-categories: - get: - description: Returns active sub-categories for the given category ID - parameters: - - description: Category ID - in: path - name: categoryId - required: true - type: integer - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List sub-categories for a course category - tags: - - course-management - /api/v1/course-management/courses: - get: - description: Returns all courses with pagination - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List all courses - tags: - - course-management - post: - consumes: - - application/json - description: Legacy-compatible endpoint for creating a course - parameters: - - description: Create course payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createCourseReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create course - tags: - - course-management - /api/v1/course-management/courses/{courseId}: - delete: - description: Legacy-compatible endpoint for deleting a course - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Delete course - tags: - - course-management - get: - description: Returns one course by ID - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get course detail - tags: - - course-management - put: - consumes: - - application/json - description: Legacy-compatible endpoint for updating a course - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - - description: Update course payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateCourseReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update course - tags: - - course-management - /api/v1/course-management/courses/{courseId}/hierarchy: - get: - description: Returns hierarchy nodes for one course including levels/modules/sub-modules - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get hierarchy for a course - tags: - - course-management - /api/v1/course-management/courses/{courseId}/learning-path: - get: - description: Legacy-compatible endpoint for course learning path - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get course learning path - tags: - - course-management - /api/v1/course-management/courses/{courseId}/levels: - get: - description: Returns all active levels for one course - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List levels by course - tags: - - course-management - /api/v1/course-management/courses/{courseId}/thumbnail: - post: - consumes: - - application/json - description: Legacy-compatible endpoint for updating course thumbnail - parameters: - - description: Course ID - in: path - name: courseId - required: true - type: integer - - description: Update course thumbnail payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateCourseThumbnailReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update course thumbnail - tags: - - course-management - /api/v1/course-management/hierarchy: - get: - description: 'Returns full hierarchy: category -> sub-category -> course' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get unified course hierarchy - tags: - - course-management - /api/v1/course-management/human-language/courses: - get: - description: Returns all courses under Human Language category - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List Human Language courses - tags: - - course-management - /api/v1/course-management/human-language/sub-categories: - get: - description: Returns active sub-categories under Human Language category - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List Human Language sub-categories - tags: - - course-management - /api/v1/course-management/levels: - get: - description: Returns all levels with pagination - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List all levels - tags: - - course-management - post: - consumes: - - application/json - description: Creates a level under a course. cefr_level is a short level code - or label (1–64 characters), unique per course; optional title defaults to - that value; optional description and thumbnail - parameters: - - description: Create level payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createLevelReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create level - tags: - - course-management - /api/v1/course-management/levels/{levelId}: - get: - description: Returns one level by ID - parameters: - - description: Level ID - in: path - name: levelId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get level detail - tags: - - course-management - put: - consumes: - - application/json - description: Updates level title, description, thumbnail, display order, and - active flag - parameters: - - description: Level ID - in: path - name: levelId - required: true - type: integer - - description: Update level payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateLevelReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update level - tags: - - course-management - /api/v1/course-management/levels/{levelId}/modules: - get: - description: Returns all active modules for one level - parameters: - - description: Level ID - in: path - name: levelId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List modules by level - tags: - - course-management - /api/v1/course-management/module-capstones: - post: - consumes: - - application/json - description: Creates a module-level capstone with a new CAPSTONE question set - and ordered questions - parameters: - - description: Create module capstone payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createModuleCapstoneReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create module capstone - tags: - - course-management - /api/v1/course-management/module-capstones/{moduleCapstoneId}: - delete: - description: Deletes the module capstone and its backing question set - parameters: - - description: Module capstone ID - in: path - name: moduleCapstoneId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Delete module capstone - tags: - - course-management - get: - description: Returns one module capstone with question-set fields and the ordered - question list - parameters: - - description: Module capstone ID - in: path - name: moduleCapstoneId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get module capstone detail - tags: - - course-management - put: - consumes: - - application/json - description: Updates module capstone content, question-set assessment settings, - and optionally replaces the question list - parameters: - - description: Module capstone ID - in: path - name: moduleCapstoneId - required: true - type: integer - - description: Update module capstone payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateModuleCapstoneReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update module capstone - tags: - - course-management - /api/v1/course-management/modules: - get: - description: Returns all modules with pagination - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List all modules - tags: - - course-management - post: - consumes: - - application/json - description: Creates a module under a level; optional icon_url stores a module - icon image URL - parameters: - - description: Create module payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createModuleReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' summary: Create module tags: - - course-management - /api/v1/course-management/modules/{moduleId}: - get: - description: Returns one module by ID + - modules + /api/v1/courses/{id}: + delete: parameters: - - description: Module ID + - description: Course ID in: path - name: moduleId + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Delete course + tags: + - courses + get: + parameters: + - description: Course ID + in: path + name: id required: true type: integer produces: @@ -3466,38 +2441,28 @@ paths: description: OK schema: $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' "404": description: Not Found schema: $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get module detail + summary: Get course by ID tags: - - course-management + - courses put: consumes: - application/json - description: Updates module title, description, icon URL, display order, and - active flag parameters: - - description: Module ID + - description: Course ID in: path - name: moduleId + name: id required: true type: integer - - description: Update module payload + - description: Fields to update in: body name: body required: true schema: - $ref: '#/definitions/handlers.updateModuleReq' + $ref: '#/definitions/domain.UpdateCourseInput' produces: - application/json responses: @@ -3505,604 +2470,24 @@ paths: description: OK schema: $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' "404": description: Not Found schema: $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update module + summary: Update course tags: - - course-management - /api/v1/course-management/modules/{moduleId}/capstones: + - courses + /api/v1/courses/{id}/practices: get: - description: Returns active module capstones with question-set settings and - question counts parameters: - - description: Module ID + - description: Course ID in: path - name: moduleId + name: id required: true type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List capstones under module + responses: {} tags: - - course-management - /api/v1/course-management/modules/{moduleId}/sub-modules: - get: - description: Returns all active sub-modules for one module - parameters: - - description: Module ID - in: path - name: moduleId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List sub-modules by module - tags: - - course-management - /api/v1/course-management/practices/{practiceId}: - get: - consumes: - - application/json - description: Returns one active practice by practice ID - parameters: - - description: Practice ID - in: path - name: practiceId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get practice detail - tags: - - course-management - /api/v1/course-management/practices/{practiceId}/detail: - get: - description: Returns one active practice with question-set fields and the ordered - question list (full item detail) - parameters: - - description: Practice ID (sub_module_practices.id) - in: path - name: practiceId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get practice with full question list - tags: - - course-management - /api/v1/course-management/sub-categories: - get: - description: Returns all active course sub-categories - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List course sub-categories - tags: - - course-management - post: - consumes: - - application/json - description: Creates a sub-category under a course category - parameters: - - description: Create sub-category payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createCourseSubCategoryReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create course sub-category - tags: - - course-management - /api/v1/course-management/sub-categories/{subCategoryId}/courses: - get: - description: Returns courses for one sub-category - parameters: - - description: Sub-category ID - in: path - name: subCategoryId - required: true - type: integer - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List courses by sub-category - tags: - - course-management - /api/v1/course-management/sub-module-capstones: - post: - consumes: - - application/json - description: Creates a capstone assessment with a new CAPSTONE question set, - metadata, and ordered questions - parameters: - - description: Create capstone payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createSubModuleCapstoneReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create capstone under sub-module - tags: - - course-management - /api/v1/course-management/sub-module-lessons: - post: - consumes: - - application/json - description: Creates a sub-module lesson with teaching content (text, image, - audio, video URLs) and optional thumbnail - parameters: - - description: Create lesson payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createSubModuleLessonReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create lesson under sub-module - tags: - - course-management - /api/v1/course-management/sub-module-lessons/{lessonId}: - get: - consumes: - - application/json - description: Returns one lesson detail by lesson ID (active or inactive) - parameters: - - description: Lesson ID - in: path - name: lessonId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get lesson detail - tags: - - course-management - put: - consumes: - - application/json - description: Updates lesson teaching content, thumbnail, ordering, and active - flag - parameters: - - description: Lesson ID - in: path - name: lessonId - required: true - type: integer - - description: Update lesson payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.updateSubModuleLessonReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Update lesson detail - tags: - - course-management - /api/v1/course-management/sub-module-practices: - post: - consumes: - - application/json - description: Creates a sub-module practice with metadata and linked question - set - parameters: - - description: Create practice payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createSubModulePracticeReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create practice under sub-module - tags: - - course-management - /api/v1/course-management/sub-module-videos: - post: - consumes: - - application/json - description: Creates a video under a sub-module - parameters: - - description: Create sub-module video payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createSubModuleVideoReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create sub-module video - tags: - - course-management - /api/v1/course-management/sub-modules: - get: - description: Returns all sub-modules with pagination - parameters: - - description: Offset - in: query - name: offset - type: integer - - description: Limit - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List all sub-modules - tags: - - course-management - post: - consumes: - - application/json - description: Creates a sub-module under a module; optional thumbnail (image - URL) and tips text - parameters: - - description: Create sub-module payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.createSubModuleReq' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Create sub-module - tags: - - course-management - /api/v1/course-management/sub-modules/{subModuleId}: - get: - description: Returns one sub-module by ID - parameters: - - description: Sub-module ID - in: path - name: subModuleId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get sub-module detail - tags: - - course-management - /api/v1/course-management/sub-modules/{subModuleId}/capstones: - get: - description: Returns active capstones for a sub-module with question-set settings - and question counts - parameters: - - description: Sub-module ID - in: path - name: subModuleId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: List capstones under sub-module - tags: - - course-management - /api/v1/course-management/sub-modules/{subModuleId}/lessons: - get: - consumes: - - application/json - description: Returns lessons for a sub-module. By default only active lessons; - pass include_inactive=true to include inactive rows (e.g. admin / CMS). - parameters: - - description: Sub-module ID - in: path - name: subModuleId - required: true - type: integer - - description: Include inactive lessons - in: query - name: include_inactive - type: boolean - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get lessons under sub-module - tags: - - course-management - /api/v1/course-management/sub-modules/{subModuleId}/practices: - get: - consumes: - - application/json - description: Returns all active practices attached to a sub-module - parameters: - - description: Sub-module ID - in: path - name: subModuleId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get practices under sub-module - tags: - - course-management + - practices /api/v1/files/audio: post: consumes: @@ -4160,86 +2545,6 @@ paths: summary: Get presigned URL for a file tags: - files - /api/v1/internal/db/clear-course-management: - post: - consumes: - - application/json - description: Truncates course_categories, courses, and sub_courses (same scope - as reset-reseed) without re-inserting seed SQL. - parameters: - - description: Optional token when DB_RESET_RESEED_TOKEN is set - in: header - name: X-Seed-Reset-Token - type: string - - description: Confirmation payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.clearCourseManagementReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "403": - description: Forbidden - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Clear course management hierarchy data only - tags: - - internal - /api/v1/internal/db/reset-reseed: - post: - consumes: - - application/json - description: Truncates course_categories, courses, and sub_courses. If seed - SQL contains INSERTs for those tables (e.g. 007_course_management_seed.sql), - they are replayed; otherwise tables are left empty after truncate. - parameters: - - description: Reset token configured in DB_RESET_RESEED_TOKEN - in: header - name: X-Seed-Reset-Token - required: true - type: string - - description: Confirmation payload - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.resetAndReseedReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "403": - description: Forbidden - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Reset and reseed database - tags: - - internal /api/v1/internal/users/purge-due-deletions: post: description: Worker-safe purge for due self-deletion requests @@ -4521,6 +2826,54 @@ paths: summary: Get issues for a specific user tags: - issues + /api/v1/lessons/{id}: + delete: + parameters: + - description: Lesson ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - lessons + get: + parameters: + - description: Lesson ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - lessons + put: + parameters: + - description: Lesson ID + in: path + name: id + required: true + type: integer + - description: Fields to update + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.UpdateLessonInput' + responses: {} + tags: + - lessons + /api/v1/lessons/{id}/practices: + get: + parameters: + - description: Lesson ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - practices /api/v1/logs: get: description: Fetches application logs from MongoDB with pagination, level filtering, @@ -4563,6 +2916,100 @@ paths: summary: Retrieve application logs with filtering and pagination tags: - Logs + /api/v1/modules/{id}: + delete: + parameters: + - description: Module ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - modules + get: + parameters: + - description: Module ID + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + tags: + - modules + put: + parameters: + - description: Module ID + in: path + name: id + required: true + type: integer + - description: Fields to update + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.UpdateModuleInput' + responses: {} + tags: + - modules + /api/v1/modules/{id}/practices: + get: + parameters: + - description: Module ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - practices + /api/v1/modules/{moduleId}/lessons: + get: + parameters: + - description: Module ID + in: path + name: moduleId + required: true + type: integer + - default: 20 + description: Page size + in: query + name: limit + type: integer + - default: 0 + description: Offset + in: query + name: offset + type: integer + responses: {} + tags: + - lessons + post: + consumes: + - application/json + parameters: + - description: Module ID + in: path + name: moduleId + required: true + type: integer + - description: Lesson + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.CreateLessonInput' + produces: + - application/json + responses: {} + summary: Create lesson + tags: + - lessons /api/v1/notifications/bulk-email: post: consumes: @@ -5088,6 +3535,57 @@ paths: summary: Handle ArifPay webhook tags: - payments + /api/v1/practices: + post: + consumes: + - application/json + parameters: + - description: 'Practice (parent_kind: COURSE | MODULE | LESSON)' + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.CreatePracticeInput' + responses: {} + tags: + - practices + /api/v1/practices/{id}: + delete: + parameters: + - description: Practice ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - practices + get: + parameters: + - description: Practice ID + in: path + name: id + required: true + type: integer + responses: {} + tags: + - practices + put: + parameters: + - description: Practice ID + in: path + name: id + required: true + type: integer + - description: Fields to update (parent is immutable) + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.UpdatePracticeInput' + responses: {} + tags: + - practices /api/v1/practices/{practiceId}/questions: get: description: Returns paginated questions for a practice(question-set), including @@ -5134,6 +3632,203 @@ paths: summary: Get questions by practice tags: - question-set-items + /api/v1/programs: + get: + description: Paginated list of programs + parameters: + - default: 20 + description: Page size + in: query + name: limit + type: integer + - default: 0 + description: Offset + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: List programs + tags: + - programs + post: + consumes: + - application/json + description: Create a top-level LMS program + parameters: + - description: Program + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.CreateProgramInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/domain.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Create program + tags: + - programs + /api/v1/programs/{id}: + delete: + parameters: + - description: Program ID + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Delete program + tags: + - programs + get: + parameters: + - description: Program ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Get program by ID + tags: + - programs + put: + consumes: + - application/json + parameters: + - description: Program ID + in: path + name: id + required: true + type: integer + - description: Fields to update + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.UpdateProgramInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Update program + tags: + - programs + /api/v1/programs/{id}/courses: + get: + parameters: + - description: Program ID + in: path + name: id + required: true + type: integer + - default: 20 + description: Page size + in: query + name: limit + type: integer + - default: 0 + description: Offset + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.Response' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: List courses by program + tags: + - courses + post: + consumes: + - application/json + description: Create a course under a program + parameters: + - description: Program ID + in: path + name: id + required: true + type: integer + - description: Course + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.CreateCourseInput' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/domain.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Create course + tags: + - courses /api/v1/progress/practices/{id}/complete: post: description: Marks a practice question set as completed for the authenticated @@ -5582,38 +4277,6 @@ paths: summary: Get question sets by owner tags: - question-sets - /api/v1/question-sets/sub-courses/{subCourseId}/entry-assessment: - get: - description: Returns the published INITIAL_ASSESSMENT question set for the given - sub-course - parameters: - - description: Sub-course ID - in: path - name: subCourseId - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.Response' - "400": - description: Bad Request - schema: - $ref: '#/definitions/domain.ErrorResponse' - "404": - description: Not Found - schema: - $ref: '#/definitions/domain.ErrorResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/domain.ErrorResponse' - summary: Get entry assessment set for a sub-course - tags: - - question-sets /api/v1/questions: get: description: Returns a paginated list of questions with optional filters