Yimaru-BackEnd/postman/Dynamic-Question-Type-Builder.postman_collection.json

664 lines
23 KiB
JSON

{
"info": {
"_postman_id": "c9e5e08f-e878-4d8a-b24c-5f866eb4c735",
"name": "Dynamic Question Type Builder - Runtime Complete",
"description": "Complete collection for the new dynamic question type builder flow: component catalog, definition schema CRUD, dynamic payload validation, and DYNAMIC question lifecycle.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{access_token}}",
"type": "string"
}
]
},
"variable": [
{
"key": "base_url",
"value": "http://localhost:8080"
},
{
"key": "access_token",
"value": ""
},
{
"key": "definition_key",
"value": "dynamic_builder_{{$timestamp}}"
},
{
"key": "dynamic_definition_id",
"value": ""
},
{
"key": "dynamic_question_id",
"value": ""
}
],
"item": [
{
"name": "01 - Builder Catalog and Validation",
"item": [
{
"name": "Get Component Catalog",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/component-catalog",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"component-catalog"
]
}
},
"response": []
},
{
"name": "Validate Definition (Valid)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"const body = pm.response.json();",
"pm.test(\"valid = true\", function () {",
" pm.expect(body.data.valid).to.eql(true);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"stimulus_component_kinds\": [\"QUESTION_TEXT\", \"IMAGE\", \"TABLE\"],\n \"response_component_kinds\": [\"OPTION\", \"ANSWER_TIMER\"]\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/validate-question-type-definition",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"validate-question-type-definition"
]
}
},
"response": []
},
{
"name": "Validate Definition (Invalid - Timer Only)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400\", function () {",
" pm.response.to.have.status(400);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"stimulus_component_kinds\": [\"QUESTION_TEXT\"],\n \"response_component_kinds\": [\"ANSWER_TIMER\"]\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/validate-question-type-definition",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"validate-question-type-definition"
]
}
},
"response": []
}
]
},
{
"name": "02 - Definition CRUD (Schema-Driven)",
"item": [
{
"name": "Create Dynamic Definition (with schema)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 201\", function () {",
" pm.response.to.have.status(201);",
"});",
"const body = pm.response.json();",
"pm.collectionVariables.set(\"dynamic_definition_id\", body.data.id);"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"key\": \"{{definition_key}}\",\n \"display_name\": \"Dynamic Grammar + Visual MCQ\",\n \"description\": \"Reusable dynamic question type with question text, image, table, and option responses.\",\n \"stimulus_component_kinds\": [\"QUESTION_TEXT\", \"IMAGE\", \"TABLE\"],\n \"response_component_kinds\": [\"OPTION\", \"ANSWER_TIMER\"],\n \"stimulus_schema\": [\n {\n \"id\": \"prompt\",\n \"kind\": \"QUESTION_TEXT\",\n \"label\": \"Prompt\",\n \"required\": true,\n \"config\": {\n \"max_length\": 1000\n }\n },\n {\n \"id\": \"illustration\",\n \"kind\": \"IMAGE\",\n \"label\": \"Supporting Image\",\n \"required\": false,\n \"config\": {\n \"allowed_formats\": [\"png\", \"jpg\", \"webp\"]\n }\n },\n {\n \"id\": \"data_table\",\n \"kind\": \"TABLE\",\n \"label\": \"Reference Table\",\n \"required\": false,\n \"config\": {\n \"max_rows\": 20,\n \"max_columns\": 8\n }\n }\n ],\n \"response_schema\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"label\": \"Answer Options\",\n \"required\": true,\n \"config\": {\n \"min_options\": 2,\n \"max_options\": 6,\n \"allow_multiple\": false\n }\n },\n {\n \"id\": \"timer\",\n \"kind\": \"ANSWER_TIMER\",\n \"label\": \"Answer Time Limit\",\n \"required\": false,\n \"config\": {\n \"min_seconds\": 5,\n \"max_seconds\": 180\n }\n }\n ],\n \"status\": \"ACTIVE\"\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions"
]
}
},
"response": []
},
{
"name": "Get Definition By ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions/{{dynamic_definition_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions",
"{{dynamic_definition_id}}"
]
}
},
"response": []
},
{
"name": "List Definitions (include system)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions?include_system=true&status=ACTIVE",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions"
],
"query": [
{
"key": "include_system",
"value": "true"
},
{
"key": "status",
"value": "ACTIVE"
}
]
}
},
"response": []
},
{
"name": "Update Definition (schema evolution)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"display_name\": \"Dynamic Grammar + Visual MCQ (Updated)\",\n \"response_component_kinds\": [\"OPTION\", \"ANSWER_TIMER\", \"SEQUENCE_ORDER\"],\n \"response_schema\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"label\": \"Answer Options\",\n \"required\": true,\n \"config\": {\n \"min_options\": 2,\n \"max_options\": 6,\n \"allow_multiple\": false\n }\n },\n {\n \"id\": \"timer\",\n \"kind\": \"ANSWER_TIMER\",\n \"label\": \"Answer Time Limit\",\n \"required\": false,\n \"config\": {\n \"min_seconds\": 5,\n \"max_seconds\": 180\n }\n },\n {\n \"id\": \"ordering\",\n \"kind\": \"SEQUENCE_ORDER\",\n \"label\": \"Optional Sequence Order\",\n \"required\": false,\n \"config\": {\n \"max_items\": 8\n }\n }\n ]\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions/{{dynamic_definition_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions",
"{{dynamic_definition_id}}"
]
}
},
"response": []
},
{
"name": "Update Definition (Invalid Schema Kind) - Expect 400",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400\", function () {",
" pm.response.to.have.status(400);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"response_schema\": [\n {\n \"id\": \"bad\",\n \"kind\": \"NON_EXISTENT_KIND\",\n \"required\": true\n }\n ]\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions/{{dynamic_definition_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions",
"{{dynamic_definition_id}}"
]
}
},
"response": []
}
]
},
{
"name": "03 - Dynamic Question Runtime",
"item": [
{
"name": "Create Dynamic Question (valid payload)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 201\", function () {",
" pm.response.to.have.status(201);",
"});",
"const body = pm.response.json();",
"pm.collectionVariables.set(\"dynamic_question_id\", body.data.id);",
"pm.test(\"Question type is DYNAMIC\", function () {",
" pm.expect(body.data.question_type).to.eql(\"DYNAMIC\");",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"question_text\": \"Complete the sentence using the table and image.\",\n \"question_type\": \"DYNAMIC\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"difficulty_level\": \"MEDIUM\",\n \"points\": 2,\n \"status\": \"DRAFT\",\n \"dynamic_payload\": {\n \"stimulus\": [\n {\n \"id\": \"prompt\",\n \"kind\": \"QUESTION_TEXT\",\n \"value\": \"Select the best completion based on the visual and table.\"\n },\n {\n \"id\": \"illustration\",\n \"kind\": \"IMAGE\",\n \"value\": \"https://cdn.example.com/images/sample-grammar-scene.jpg\"\n },\n {\n \"id\": \"data_table\",\n \"kind\": \"TABLE\",\n \"value\": {\n \"columns\": [\"Verb\", \"Past Form\"],\n \"rows\": [\n [\"go\", \"went\"],\n [\"write\", \"wrote\"]\n ]\n }\n }\n ],\n \"response\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"value\": {\n \"options\": [\n {\"id\": \"a\", \"text\": \"I goed to school\", \"is_correct\": false},\n {\"id\": \"b\", \"text\": \"I went to school\", \"is_correct\": true}\n ]\n }\n },\n {\n \"id\": \"timer\",\n \"kind\": \"ANSWER_TIMER\",\n \"value\": {\n \"seconds\": 30\n }\n }\n ]\n }\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions"
]
}
},
"response": []
},
{
"name": "Get Dynamic Question By ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/{{dynamic_question_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"{{dynamic_question_id}}"
]
}
},
"response": []
},
{
"name": "Update Dynamic Question (valid payload)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"question_text\": \"Updated: choose the best sentence.\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"question_type\": \"DYNAMIC\",\n \"status\": \"PUBLISHED\",\n \"dynamic_payload\": {\n \"stimulus\": [\n {\n \"id\": \"prompt\",\n \"kind\": \"QUESTION_TEXT\",\n \"value\": \"Pick the grammatically correct option.\"\n }\n ],\n \"response\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"value\": {\n \"options\": [\n {\"id\": \"a\", \"text\": \"He go home yesterday\", \"is_correct\": false},\n {\"id\": \"b\", \"text\": \"He went home yesterday\", \"is_correct\": true}\n ]\n }\n }\n ]\n }\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions/{{dynamic_question_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"{{dynamic_question_id}}"
]
}
},
"response": []
},
{
"name": "List Questions (question_type=DYNAMIC)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions?question_type=DYNAMIC&limit=20&offset=0",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions"
],
"query": [
{
"key": "question_type",
"value": "DYNAMIC"
},
{
"key": "limit",
"value": "20"
},
{
"key": "offset",
"value": "0"
}
]
}
},
"response": []
},
{
"name": "Search Questions",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/search?q=choose&limit=20&offset=0",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"search"
],
"query": [
{
"key": "q",
"value": "choose"
},
{
"key": "limit",
"value": "20"
},
{
"key": "offset",
"value": "0"
}
]
}
},
"response": []
}
]
},
{
"name": "04 - Negative Runtime Validation Cases",
"item": [
{
"name": "Create Dynamic Question without dynamic_payload - Expect 400",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400\", function () {",
" pm.response.to.have.status(400);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"question_text\": \"Should fail\",\n \"question_type\": \"DYNAMIC\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"difficulty_level\": \"EASY\"\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions"
]
}
},
"response": []
},
{
"name": "Create Dynamic Question with disallowed element kind - Expect 400",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400\", function () {",
" pm.response.to.have.status(400);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"question_text\": \"Should fail because AUDIO_CLIP is not allowed by selected definition\",\n \"question_type\": \"DYNAMIC\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"dynamic_payload\": {\n \"stimulus\": [\n {\n \"id\": \"audio1\",\n \"kind\": \"AUDIO_CLIP\",\n \"value\": \"https://cdn.example.com/audio/not-allowed.mp3\"\n }\n ],\n \"response\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"value\": {\n \"options\": [\n {\"id\": \"a\", \"text\": \"A\", \"is_correct\": true},\n {\"id\": \"b\", \"text\": \"B\", \"is_correct\": false}\n ]\n }\n }\n ]\n }\n}"
},
"url": {
"raw": "{{base_url}}/api/v1/questions",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions"
]
}
},
"response": []
}
]
},
{
"name": "05 - Cleanup",
"item": [
{
"name": "Delete Dynamic Question",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/{{dynamic_question_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"{{dynamic_question_id}}"
]
}
},
"response": []
},
{
"name": "Delete Dynamic Definition",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/v1/questions/type-definitions/{{dynamic_definition_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"v1",
"questions",
"type-definitions",
"{{dynamic_definition_id}}"
]
}
},
"response": []
}
]
}
]
}