{
  "$comment": "Generated at website build time by website/scripts/generate-llms.mjs from spec/api-index.json and the Python models. Do not edit.",
  "name": "pro-sejongpeia",
  "libraryVersion": "1.2.77",
  "site": "https://cassiiopeia.github.io/pro-sejongpeia/",
  "repository": "https://github.com/Cassiiopeia/pro-sejongpeia",
  "packages": {
    "java": {
      "groupId": "kr.suhsaechan",
      "artifactId": "sejongpeia",
      "requires": "Java 17+, Spring Boot 3.x (Spring auto-configuration registers the beans)"
    },
    "python": {
      "package": "pro-sejongpeia",
      "import": "sejongpeia",
      "requires": "Python 3.9+, standard library only"
    },
    "node": {
      "package": "pro-sejongpeia",
      "requires": "Node 18+, zero dependencies, ESM and CommonJS, server only"
    },
    "versionPolicy": {
      "ko": "하위 호환을 보장하지 않으니 버전을 정확히 고정하고 릴리스 노트를 읽고 올림",
      "en": "No backward-compatibility promise: pin the exact version and read the release notes before upgrading"
    }
  },
  "clients": {
    "publicData": {
      "python": "from sejongpeia import SejongPublicData\npublic_data = SejongPublicData()",
      "node": "import { SejongPublicData } from 'pro-sejongpeia';\nconst publicData = new SejongPublicData();",
      "java": "@Autowired SejongPublicData publicData; // or new SejongPublicData() without Spring"
    },
    "auth": {
      "python": "from sejongpeia import authenticate  # module functions; SejongAuthClient(...) to change settings",
      "node": "import { authenticate } from 'pro-sejongpeia';  // module functions; new SejongAuthClient({...}) to change settings",
      "java": "@Autowired SuhSejongAuthEngine authEngine; // Spring bean"
    }
  },
  "behavior": {
    "publicData": {
      "requiresLogin": false,
      "emptyValue": {
        "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
        "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
      },
      "invalidInput": {
        "ko": "잘못된 입력만 INVALID_INPUT 예외 (요청 없음)",
        "en": "Only invalid input raises INVALID_INPUT (no request is sent)"
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "valueRules": {
        "ko": "학교 원문 문자열 그대로, 값이 없으면 빈 문자열 (null 없음). views·total 은 정수, latitude·longitude 는 숫자. 쓰지 않은 학교 필드는 extra (문자열 맵)",
        "en": "Raw school strings as they are; missing values are empty strings (never null). views and total are integers, latitude and longitude are numbers. Unused school fields land in extra (string map)"
      }
    },
    "auth": {
      "requiresLogin": true,
      "failure": {
        "ko": "실패 시 SejongAuthError(ErrorCode) 예외 (자바는 SejongAuthException). 틀린 비밀번호는 재시도 없이 즉시 실패",
        "en": "Raises SejongAuthError(ErrorCode) on failure (Java: SejongAuthException). A wrong password fails at once without retry"
      },
      "securityNote": {
        "ko": "서버에서만 호출. 학번·비밀번호를 저장하거나 로그에 남기지 않음",
        "en": "Call from a server only. Never store or log the student id or password"
      }
    }
  },
  "errorCodes": [
    "INVALID_INPUT",
    "AUTHENTICATION_FAILED",
    "CONNECTION_FAILED",
    "CONNECTION_TIMEOUT",
    "SESSION_ERROR",
    "DATA_FETCH_FAILED",
    "PARSE_ERROR",
    "SSL_CONFIGURATION_ERROR",
    "ACCOUNT_LOCKED",
    "ACCOUNT_UNAVAILABLE"
  ],
  "methods": [
    {
      "id": "organization_categories",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "기관 구분 목록 (학부 20, 대학원 30 등)",
        "en": "Organization categories (undergraduate 20, graduate 30 and so on)"
      },
      "names": {
        "python": "organization_categories",
        "node": "organizationCategories",
        "java": [
          "organizationCategories"
        ]
      },
      "usage": {
        "python": "organization_categories()",
        "node": "await organizationCategories()",
        "java": [
          "organizationCategories()"
        ]
      },
      "parameters": [],
      "returns": {
        "model": "OrganizationCategory",
        "isList": true,
        "fields": [
          {
            "python": "code",
            "node": "code",
            "java": "code",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "name_en",
            "node": "nameEn",
            "java": "nameEn",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/codes/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/codes/"
      }
    },
    {
      "id": "terms",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "기관 구분의 학기 목록",
        "en": "Terms of one organization category"
      },
      "names": {
        "python": "terms",
        "node": "terms",
        "java": [
          "terms"
        ]
      },
      "usage": {
        "python": "terms(category_code)",
        "node": "await terms(categoryCode)",
        "java": [
          "terms(String categoryCode)"
        ]
      },
      "parameters": [
        {
          "name": "category_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "기관 구분 코드 (organization_categories 결과의 code, 예: 20 학부)",
            "en": "Organization category code (code from organization_categories, for example 20 for undergraduate)"
          },
          "nodeName": "categoryCode"
        }
      ],
      "returns": {
        "model": "Term",
        "isList": true,
        "fields": [
          {
            "python": "year",
            "node": "year",
            "java": "year",
            "type": "string"
          },
          {
            "python": "semester_code",
            "node": "semesterCode",
            "java": "semesterCode",
            "type": "string"
          },
          {
            "python": "code",
            "node": "code",
            "java": "code",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/codes/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/codes/"
      }
    },
    {
      "id": "departments",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "학기의 학과 목록",
        "en": "Departments of one term"
      },
      "names": {
        "python": "departments",
        "node": "departments",
        "java": [
          "departments"
        ]
      },
      "usage": {
        "python": "departments(category_code, year, semester_code)",
        "node": "await departments({ categoryCode, year, semesterCode })",
        "java": [
          "departments(String categoryCode, String year, String semesterCode)"
        ]
      },
      "parameters": [
        {
          "name": "category_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "기관 구분 코드",
            "en": "Organization category code"
          },
          "nodeName": "categoryCode"
        },
        {
          "name": "year",
          "type": "string",
          "required": true,
          "description": {
            "ko": "연도 4자리 (예: 2026)",
            "en": "Four-digit year (for example 2026)"
          },
          "nodeName": "year"
        },
        {
          "name": "semester_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학기 코드 (10 1학기, 11 하계, 20 2학기, 21 동계)",
            "en": "Semester code (10 first, 11 summer, 20 second, 21 winter)"
          },
          "nodeName": "semesterCode"
        }
      ],
      "returns": {
        "model": "Department",
        "isList": true,
        "fields": [
          {
            "python": "code",
            "node": "code",
            "java": "code",
            "type": "string"
          },
          {
            "python": "level",
            "node": "level",
            "java": "level",
            "type": "string"
          },
          {
            "python": "college_code",
            "node": "collegeCode",
            "java": "collegeCode",
            "type": "string"
          },
          {
            "python": "college_name",
            "node": "collegeName",
            "java": "collegeName",
            "type": "string"
          },
          {
            "python": "unit_code",
            "node": "unitCode",
            "java": "unitCode",
            "type": "string"
          },
          {
            "python": "unit_name",
            "node": "unitName",
            "java": "unitName",
            "type": "string"
          },
          {
            "python": "major_code",
            "node": "majorCode",
            "java": "majorCode",
            "type": "string"
          },
          {
            "python": "major_name",
            "node": "majorName",
            "java": "majorName",
            "type": "string"
          },
          {
            "python": "name_en",
            "node": "nameEn",
            "java": "nameEn",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/codes/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/codes/"
      }
    },
    {
      "id": "course_types",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "이수 구분 목록 (공필, 전필 등)",
        "en": "Course types (required, major required and so on)"
      },
      "names": {
        "python": "course_types",
        "node": "courseTypes",
        "java": [
          "courseTypes"
        ]
      },
      "usage": {
        "python": "course_types()",
        "node": "await courseTypes()",
        "java": [
          "courseTypes()"
        ]
      },
      "parameters": [],
      "returns": {
        "model": "CourseType",
        "isList": true,
        "fields": [
          {
            "python": "code",
            "node": "code",
            "java": "code",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "category_code",
            "node": "categoryCode",
            "java": "categoryCode",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/codes/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/codes/"
      }
    },
    {
      "id": "selective_domains",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "선택 교양 영역 목록",
        "en": "Elective liberal-arts domains"
      },
      "names": {
        "python": "selective_domains",
        "node": "selectiveDomains",
        "java": [
          "selectiveDomains"
        ]
      },
      "usage": {
        "python": "selective_domains()",
        "node": "await selectiveDomains()",
        "java": [
          "selectiveDomains()"
        ]
      },
      "parameters": [],
      "returns": {
        "model": "SelectiveDomain",
        "isList": true,
        "fields": [
          {
            "python": "code",
            "node": "code",
            "java": "code",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "name_en",
            "node": "nameEn",
            "java": "nameEn",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/codes/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/codes/"
      }
    },
    {
      "id": "lectures",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "개설 강좌 검색 (학과·과목명·교수명은 선택, 모두 비우면 그 학기 전체)",
        "en": "Search offered lectures (department, course name and instructor are optional; all empty returns the whole term)"
      },
      "names": {
        "python": "lectures",
        "node": "lectures",
        "java": [
          "lectures"
        ]
      },
      "usage": {
        "python": "lectures(category_code, year, semester_code, department_code=\"\", course_name=\"\", instructor_name=\"\")",
        "node": "await lectures({ categoryCode, year, semesterCode, departmentCode?, courseName?, instructorName? })",
        "java": [
          "lectures(String categoryCode, String year, String semesterCode, String departmentCode, String courseName, String instructorName)"
        ]
      },
      "parameters": [
        {
          "name": "category_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "기관 구분 코드",
            "en": "Organization category code"
          },
          "nodeName": "categoryCode"
        },
        {
          "name": "year",
          "type": "string",
          "required": true,
          "description": {
            "ko": "연도 4자리",
            "en": "Four-digit year"
          },
          "nodeName": "year"
        },
        {
          "name": "semester_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학기 코드 (10, 11, 20, 21)",
            "en": "Semester code (10, 11, 20, 21)"
          },
          "nodeName": "semesterCode"
        },
        {
          "name": "department_code",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "학과 코드 (departments 결과의 code), 비우면 전체",
            "en": "Department code (code from departments); empty means all"
          },
          "nodeName": "departmentCode"
        },
        {
          "name": "course_name",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "과목명 검색어 (앞뒤 공백 제거)",
            "en": "Course name search text (trimmed)"
          },
          "nodeName": "courseName"
        },
        {
          "name": "instructor_name",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "교수명 검색어 (앞뒤 공백 제거)",
            "en": "Instructor name search text (trimmed)"
          },
          "nodeName": "instructorName"
        }
      ],
      "returns": {
        "model": "Lecture",
        "isList": true,
        "fields": [
          {
            "python": "course_number",
            "node": "courseNumber",
            "java": "courseNumber",
            "type": "string"
          },
          {
            "python": "section",
            "node": "section",
            "java": "section",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "course_type_code",
            "node": "courseTypeCode",
            "java": "courseTypeCode",
            "type": "string"
          },
          {
            "python": "course_type_name",
            "node": "courseTypeName",
            "java": "courseTypeName",
            "type": "string"
          },
          {
            "python": "domain_code",
            "node": "domainCode",
            "java": "domainCode",
            "type": "string"
          },
          {
            "python": "domain_name",
            "node": "domainName",
            "java": "domainName",
            "type": "string"
          },
          {
            "python": "credits",
            "node": "credits",
            "java": "credits",
            "type": "string"
          },
          {
            "python": "hours",
            "node": "hours",
            "java": "hours",
            "type": "string"
          },
          {
            "python": "total_hours",
            "node": "totalHours",
            "java": "totalHours",
            "type": "string"
          },
          {
            "python": "schedule",
            "node": "schedule",
            "java": "schedule",
            "type": "string"
          },
          {
            "python": "room",
            "node": "room",
            "java": "room",
            "type": "string"
          },
          {
            "python": "instructor",
            "node": "instructor",
            "java": "instructor",
            "type": "string"
          },
          {
            "python": "grade_level",
            "node": "gradeLevel",
            "java": "gradeLevel",
            "type": "string"
          },
          {
            "python": "language_code",
            "node": "languageCode",
            "java": "languageCode",
            "type": "string"
          },
          {
            "python": "language_name",
            "node": "languageName",
            "java": "languageName",
            "type": "string"
          },
          {
            "python": "department_code",
            "node": "departmentCode",
            "java": "departmentCode",
            "type": "string"
          },
          {
            "python": "department_name",
            "node": "departmentName",
            "java": "departmentName",
            "type": "string"
          },
          {
            "python": "managing_department",
            "node": "managingDepartment",
            "java": "managingDepartment",
            "type": "string"
          },
          {
            "python": "remark",
            "node": "remark",
            "java": "remark",
            "type": "string"
          },
          {
            "python": "year",
            "node": "year",
            "java": "year",
            "type": "string"
          },
          {
            "python": "semester_code",
            "node": "semesterCode",
            "java": "semesterCode",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "notes": {
        "ko": "필터를 모두 비우면 학부 한 학기가 약 2,800행·2.4MB라서 학과 하나씩 받기를 권장. Java 는 인자 6개를 모두 넘김 (빈 값은 빈 문자열)",
        "en": "With all filters empty an undergraduate term is about 2,800 rows and 2.4 MB, so prefer one department at a time. Java takes all six arguments (use an empty string for empty)"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/lectures/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/lectures/"
      }
    },
    {
      "id": "curriculum_courses",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "학과 교육과정의 과목 1건 (학년, 학기, 이수구분, 학점, 교과목 개요)",
        "en": "One course of a department curriculum (grade, semester, course type, credits, overview)"
      },
      "names": {
        "python": "curriculum_courses",
        "node": "curriculumCourses",
        "java": [
          "curriculumCourses"
        ]
      },
      "usage": {
        "python": "curriculum_courses(department_code, course_number)",
        "node": "await curriculumCourses({ departmentCode, courseNumber })",
        "java": [
          "curriculumCourses(String departmentCode, String courseNumber)"
        ]
      },
      "parameters": [
        {
          "name": "department_code",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학과 코드 (departments 결과의 code)",
            "en": "Department code (code from departments)"
          },
          "nodeName": "departmentCode"
        },
        {
          "name": "course_number",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학수번호 (lectures 결과의 course_number)",
            "en": "Course number (course_number from lectures)"
          },
          "nodeName": "courseNumber"
        }
      ],
      "returns": {
        "model": "CurriculumCourse",
        "isList": true,
        "fields": [
          {
            "python": "department_code",
            "node": "departmentCode",
            "java": "departmentCode",
            "type": "string"
          },
          {
            "python": "department_name",
            "node": "departmentName",
            "java": "departmentName",
            "type": "string"
          },
          {
            "python": "category_code",
            "node": "categoryCode",
            "java": "categoryCode",
            "type": "string"
          },
          {
            "python": "year",
            "node": "year",
            "java": "year",
            "type": "string"
          },
          {
            "python": "course_number",
            "node": "courseNumber",
            "java": "courseNumber",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "course_type_code",
            "node": "courseTypeCode",
            "java": "courseTypeCode",
            "type": "string"
          },
          {
            "python": "course_type_name",
            "node": "courseTypeName",
            "java": "courseTypeName",
            "type": "string"
          },
          {
            "python": "credits",
            "node": "credits",
            "java": "credits",
            "type": "string"
          },
          {
            "python": "lecture_hours",
            "node": "lectureHours",
            "java": "lectureHours",
            "type": "string"
          },
          {
            "python": "practice_hours",
            "node": "practiceHours",
            "java": "practiceHours",
            "type": "string"
          },
          {
            "python": "total_hours",
            "node": "totalHours",
            "java": "totalHours",
            "type": "string"
          },
          {
            "python": "grade_level",
            "node": "gradeLevel",
            "java": "gradeLevel",
            "type": "string"
          },
          {
            "python": "semester_code",
            "node": "semesterCode",
            "java": "semesterCode",
            "type": "string"
          },
          {
            "python": "semester_name",
            "node": "semesterName",
            "java": "semesterName",
            "type": "string"
          },
          {
            "python": "overview",
            "node": "overview",
            "java": "overview",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": {
          "ko": "학과 코드나 학수번호가 비면 INVALID_INPUT (요청 없음). 그 학과 교육과정에 없는 과목은 빈 목록 (정상)",
          "en": "INVALID_INPUT when the department code or course number is blank (no request). A course not in that curriculum gives an empty list (valid)"
        }
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/curriculum/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/curriculum/"
      }
    },
    {
      "id": "calendar",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "학사일정 (기간, 분류)",
        "en": "Academic calendar events (date range, category)"
      },
      "names": {
        "python": "calendar",
        "node": "calendar",
        "java": [
          "calendar"
        ]
      },
      "usage": {
        "python": "calendar(start, end, category_code=\"0001\")",
        "node": "await calendar({ start, end, categoryCode? })",
        "java": [
          "calendar(String startDate, String endDate)",
          "calendar(String startDate, String endDate, String categoryCode)"
        ]
      },
      "parameters": [
        {
          "name": "start",
          "type": "string",
          "required": true,
          "description": {
            "ko": "시작일 yyyy-MM-dd",
            "en": "Start date yyyy-MM-dd"
          },
          "nodeName": "start"
        },
        {
          "name": "end",
          "type": "string",
          "required": true,
          "description": {
            "ko": "종료일 yyyy-MM-dd",
            "en": "End date yyyy-MM-dd"
          },
          "nodeName": "end"
        },
        {
          "name": "category_code",
          "type": "string",
          "required": false,
          "default": "0001",
          "description": {
            "ko": "일정 분류 (0001 학부, 0002~0007 대학원 계열)",
            "en": "Calendar category (0001 undergraduate, 0002 to 0007 graduate schools)"
          },
          "nodeName": "categoryCode"
        }
      ],
      "returns": {
        "model": "CalendarEvent",
        "isList": true,
        "fields": [
          {
            "python": "year",
            "node": "year",
            "java": "year",
            "type": "string"
          },
          {
            "python": "month",
            "node": "month",
            "java": "month",
            "type": "string"
          },
          {
            "python": "category_code",
            "node": "categoryCode",
            "java": "categoryCode",
            "type": "string"
          },
          {
            "python": "category_name",
            "node": "categoryName",
            "java": "categoryName",
            "type": "string"
          },
          {
            "python": "title",
            "node": "title",
            "java": "title",
            "type": "string"
          },
          {
            "python": "title_en",
            "node": "titleEn",
            "java": "titleEn",
            "type": "string"
          },
          {
            "python": "start_date",
            "node": "startDate",
            "java": "startDate",
            "type": "string"
          },
          {
            "python": "end_date",
            "node": "endDate",
            "java": "endDate",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/calendar/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/calendar/"
      }
    },
    {
      "id": "graduate_calendar",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "대학원 사이트별 한 달 학사일정",
        "en": "One month of a graduate school site calendar"
      },
      "names": {
        "python": "graduate_calendar",
        "node": "graduateCalendar",
        "java": [
          "graduateCalendar"
        ]
      },
      "usage": {
        "python": "graduate_calendar(site_id, year, month)",
        "node": "await graduateCalendar({ siteId, year, month })",
        "java": [
          "graduateCalendar(String siteId, int year, int month)"
        ]
      },
      "parameters": [
        {
          "name": "site_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학교의 대학원 사이트 이름 (graduate, gsi, mba, pub, tourgrad, edu, arts 등), 소문자·숫자·하이픈만",
            "en": "The school's graduate site name (graduate, gsi, mba, pub, tourgrad, edu, arts and so on); lowercase letters, digits and hyphens only"
          },
          "nodeName": "siteId"
        },
        {
          "name": "year",
          "type": "integer",
          "required": true,
          "description": {
            "ko": "연도 (예: 2026)",
            "en": "Year (for example 2026)"
          },
          "nodeName": "year"
        },
        {
          "name": "month",
          "type": "integer",
          "required": true,
          "description": {
            "ko": "월 1~12",
            "en": "Month 1 to 12"
          },
          "nodeName": "month"
        }
      ],
      "returns": {
        "model": "CalendarEvent",
        "isList": true,
        "fields": [
          {
            "python": "year",
            "node": "year",
            "java": "year",
            "type": "string"
          },
          {
            "python": "month",
            "node": "month",
            "java": "month",
            "type": "string"
          },
          {
            "python": "category_code",
            "node": "categoryCode",
            "java": "categoryCode",
            "type": "string"
          },
          {
            "python": "category_name",
            "node": "categoryName",
            "java": "categoryName",
            "type": "string"
          },
          {
            "python": "title",
            "node": "title",
            "java": "title",
            "type": "string"
          },
          {
            "python": "title_en",
            "node": "titleEn",
            "java": "titleEn",
            "type": "string"
          },
          {
            "python": "start_date",
            "node": "startDate",
            "java": "startDate",
            "type": "string"
          },
          {
            "python": "end_date",
            "node": "endDate",
            "java": "endDate",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": {
          "ko": "site_id 형태가 틀리면 INVALID_INPUT (요청 없음)",
          "en": "INVALID_INPUT when site_id has the wrong form (no request)"
        }
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "notes": {
        "ko": "start_date·end_date 는 MM.dd 형태 (calendar 는 yyyy-MM-dd). 빈 달은 빈 목록 (정상)",
        "en": "start_date and end_date are MM.dd here (calendar gives yyyy-MM-dd). An empty month gives an empty list (valid)"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/calendar/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/calendar/"
      }
    },
    {
      "id": "dormitory_menu",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "기숙사 일주일 식단 (7일, 조식·중식·석식·대체)",
        "en": "Dormitory weekly menu (7 days: breakfast, lunch, dinner, alternative)"
      },
      "names": {
        "python": "dormitory_menu",
        "node": "dormitoryMenu",
        "java": [
          "dormitoryMenu"
        ]
      },
      "usage": {
        "python": "dormitory_menu(location=\"SJ\")",
        "node": "await dormitoryMenu(location?)",
        "java": [
          "dormitoryMenu()",
          "dormitoryMenu(String location)"
        ]
      },
      "parameters": [
        {
          "name": "location",
          "type": "string",
          "required": false,
          "default": "SJ",
          "description": {
            "ko": "기숙사 위치 코드 (기본 SJ, 다른 값은 확인하지 않음)",
            "en": "Dormitory location code (default SJ; other values are unverified)"
          },
          "nodeName": "location"
        }
      ],
      "returns": {
        "model": "DormitoryMenuDay",
        "isList": true,
        "fields": [
          {
            "python": "date",
            "node": "date",
            "java": "date",
            "type": "string"
          },
          {
            "python": "breakfast",
            "node": "breakfast",
            "java": "breakfast",
            "type": "string"
          },
          {
            "python": "lunch",
            "node": "lunch",
            "java": "lunch",
            "type": "string"
          },
          {
            "python": "dinner",
            "node": "dinner",
            "java": "dinner",
            "type": "string"
          },
          {
            "python": "alternative",
            "node": "alternative",
            "java": "alternative",
            "type": "string"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/dormitory/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/dormitory/"
      }
    },
    {
      "id": "dormitory_notices",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "기숙사 공지 목록 (고정 공지와 일반 공지, 전체 건수)",
        "en": "Dormitory notices (pinned and regular, with total count)"
      },
      "names": {
        "python": "dormitory_notices",
        "node": "dormitoryNotices",
        "java": [
          "dormitoryNotices"
        ]
      },
      "usage": {
        "python": "dormitory_notices(page=1, rows=10, keyword=\"\", location=\"SJ\")",
        "node": "await dormitoryNotices({ page?, rows?, keyword?, location? } = {})",
        "java": [
          "dormitoryNotices()",
          "dormitoryNotices(int page, int rows, String keyword, String location)"
        ]
      },
      "parameters": [
        {
          "name": "page",
          "type": "integer",
          "required": false,
          "default": 1,
          "description": {
            "ko": "쪽 번호 (1부터)",
            "en": "Page number (from 1)"
          },
          "nodeName": "page"
        },
        {
          "name": "rows",
          "type": "integer",
          "required": false,
          "default": 10,
          "description": {
            "ko": "쪽당 건수",
            "en": "Rows per page"
          },
          "nodeName": "rows"
        },
        {
          "name": "keyword",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "제목 검색어",
            "en": "Title search text"
          },
          "nodeName": "keyword"
        },
        {
          "name": "location",
          "type": "string",
          "required": false,
          "default": "SJ",
          "description": {
            "ko": "기숙사 위치 코드",
            "en": "Dormitory location code"
          },
          "nodeName": "location"
        }
      ],
      "returns": {
        "model": "DormitoryNotices",
        "isList": false,
        "fields": [
          {
            "python": "total",
            "node": "total",
            "java": "total",
            "type": "integer"
          },
          {
            "python": "pinned",
            "node": "pinned",
            "java": "pinned",
            "type": "DormitoryNotice[]"
          },
          {
            "python": "items",
            "node": "items",
            "java": "items",
            "type": "DormitoryNotice[]"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "{ total: 0, pinned: [], items: [] }",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "notes": {
        "ko": "작성자 정보는 반환하지 않음. 결과 없음은 장애가 아니라 total 0",
        "en": "Author fields are not returned. No results is total 0, not an outage"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/dormitory/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/dormitory/"
      }
    },
    {
      "id": "cafeteria_menu",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "학생식당 한 곳의 메뉴",
        "en": "Menu of one student cafeteria"
      },
      "names": {
        "python": "cafeteria_menu",
        "node": "cafeteriaMenu",
        "java": [
          "cafeteriaMenu"
        ]
      },
      "usage": {
        "python": "cafeteria_menu(place_id)",
        "node": "await cafeteriaMenu(placeId)",
        "java": [
          "cafeteriaMenu(String placeId)"
        ]
      },
      "parameters": [
        {
          "name": "place_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학교의 식당 번호 (cafeteria_places 결과의 place_id). 빈 목록이 번호가 틀렸다는 증거는 아님",
            "en": "The school's cafeteria number (place_id from cafeteria_places). An empty list does not prove the number is wrong"
          },
          "nodeName": "placeId"
        }
      ],
      "returns": {
        "model": "CafeteriaMenuItem",
        "isList": true,
        "fields": [
          {
            "python": "building_name",
            "node": "buildingName",
            "java": "buildingName",
            "type": "string"
          },
          {
            "python": "location",
            "node": "location",
            "java": "location",
            "type": "string"
          },
          {
            "python": "place_id",
            "node": "placeId",
            "java": "placeId",
            "type": "string"
          },
          {
            "python": "place_name",
            "node": "placeName",
            "java": "placeName",
            "type": "string"
          },
          {
            "python": "date",
            "node": "date",
            "java": "date",
            "type": "string"
          },
          {
            "python": "day",
            "node": "day",
            "java": "day",
            "type": "string"
          },
          {
            "python": "meal_type_id",
            "node": "mealTypeId",
            "java": "mealTypeId",
            "type": "string"
          },
          {
            "python": "meal_name",
            "node": "mealName",
            "java": "mealName",
            "type": "string"
          },
          {
            "python": "menu_name",
            "node": "menuName",
            "java": "menuName",
            "type": "string"
          },
          {
            "python": "price",
            "node": "price",
            "java": "price",
            "type": "string"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/cafeteria/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/cafeteria/"
      }
    },
    {
      "id": "cafeteria_places",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "학식 식당 목록 (번호 1부터 상한까지 메뉴를 조회해 모음)",
        "en": "Cafeteria list (built by asking menus for number 1 up to the limit)"
      },
      "names": {
        "python": "cafeteria_places",
        "node": "cafeteriaPlaces",
        "java": [
          "cafeteriaPlaces"
        ]
      },
      "usage": {
        "python": "cafeteria_places(max_place_id=10)",
        "node": "await cafeteriaPlaces({ maxPlaceId? } = {})",
        "java": [
          "cafeteriaPlaces()",
          "cafeteriaPlaces(int maxPlaceId)"
        ]
      },
      "parameters": [
        {
          "name": "max_place_id",
          "type": "integer",
          "required": false,
          "default": 10,
          "description": {
            "ko": "조회할 식당 번호 상한 (1~50, 기본 10)",
            "en": "Highest cafeteria number to ask (1 to 50, default 10)"
          },
          "nodeName": "maxPlaceId"
        }
      ],
      "returns": {
        "model": "CafeteriaPlace",
        "isList": true,
        "fields": [
          {
            "python": "place_id",
            "node": "placeId",
            "java": "placeId",
            "type": "string"
          },
          {
            "python": "place_name",
            "node": "placeName",
            "java": "placeName",
            "type": "string"
          },
          {
            "python": "building_name",
            "node": "buildingName",
            "java": "buildingName",
            "type": "string"
          },
          {
            "python": "location",
            "node": "location",
            "java": "location",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": {
          "ko": "max_place_id 가 1~50 밖이거나 정수가 아니면 INVALID_INPUT (요청 없음)",
          "en": "INVALID_INPUT when max_place_id is outside 1 to 50 or not an integer (no request)"
        }
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1 to max_place_id",
      "notes": {
        "ko": "요청을 번호만큼 차례로 보내는 유일한 메서드 (기본 10건, 최대 50건). 하나라도 실패하면 목록 전체가 실패(마지막 캐시 또는 빈 목록)해서 일부만 캐시하지 않음. 결과는 번호 순서, 캐시는 max_place_id 별. 메뉴가 없는 식당은 목록에서 빠짐",
        "en": "The only method that sends several requests, one after the other (10 by default, at most 50). One failure fails the whole list (last cache or empty list), so a partial list is never cached. Result in number order, cached per max_place_id. A cafeteria with no menu is missing"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/cafeteria/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/cafeteria/"
      }
    },
    {
      "id": "campus_places",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "캠퍼스 지도의 장소 (위도·경도 포함)",
        "en": "Campus map places (with latitude and longitude)"
      },
      "names": {
        "python": "campus_places",
        "node": "campusPlaces",
        "java": [
          "campusPlaces"
        ]
      },
      "usage": {
        "python": "campus_places(place_type=\"\")",
        "node": "await campusPlaces(placeType?)",
        "java": [
          "campusPlaces()",
          "campusPlaces(String placeType)"
        ]
      },
      "parameters": [
        {
          "name": "place_type",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "장소 종류 (학교 값 그대로), 비우면 전체",
            "en": "Place type (the school's value); empty means all"
          },
          "nodeName": "placeType"
        }
      ],
      "returns": {
        "model": "CampusPlace",
        "isList": true,
        "fields": [
          {
            "python": "id",
            "node": "id",
            "java": "id",
            "type": "string"
          },
          {
            "python": "name",
            "node": "name",
            "java": "name",
            "type": "string"
          },
          {
            "python": "name_en",
            "node": "nameEn",
            "java": "nameEn",
            "type": "string"
          },
          {
            "python": "place_type",
            "node": "placeType",
            "java": "placeType",
            "type": "string"
          },
          {
            "python": "category",
            "node": "category",
            "java": "category",
            "type": "string"
          },
          {
            "python": "latitude",
            "node": "latitude",
            "java": "latitude",
            "type": "number"
          },
          {
            "python": "longitude",
            "node": "longitude",
            "java": "longitude",
            "type": "number"
          },
          {
            "python": "info",
            "node": "info",
            "java": "info",
            "type": "string"
          },
          {
            "python": "phone",
            "node": "phone",
            "java": "phone",
            "type": "string"
          },
          {
            "python": "description",
            "node": "description",
            "java": "description",
            "type": "string"
          },
          {
            "python": "extra",
            "node": "extra",
            "java": "extra",
            "type": "object<string,string>"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/campus-places/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/campus-places/"
      }
    },
    {
      "id": "extracurricular_events",
      "group": "public_data",
      "requiresLogin": false,
      "summary": {
        "ko": "비교과 프로그램 일정",
        "en": "Extracurricular program events"
      },
      "names": {
        "python": "extracurricular_events",
        "node": "extracurricularEvents",
        "java": [
          "extracurricularEvents"
        ]
      },
      "usage": {
        "python": "extracurricular_events(start, end, category=\"\")",
        "node": "await extracurricularEvents({ start, end, category? })",
        "java": [
          "extracurricularEvents(String startDate, String endDate)",
          "extracurricularEvents(String startDate, String endDate, String category)"
        ]
      },
      "parameters": [
        {
          "name": "start",
          "type": "string",
          "required": true,
          "description": {
            "ko": "시작일 yyyy-MM-dd",
            "en": "Start date yyyy-MM-dd"
          },
          "nodeName": "start"
        },
        {
          "name": "end",
          "type": "string",
          "required": true,
          "description": {
            "ko": "종료일 yyyy-MM-dd",
            "en": "End date yyyy-MM-dd"
          },
          "nodeName": "end"
        },
        {
          "name": "category",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "비교과 분류 (학교 값 그대로), 비우면 전체",
            "en": "Event category (the school's value); empty means all"
          },
          "nodeName": "category"
        }
      ],
      "returns": {
        "model": "ExtracurricularEvent",
        "isList": true,
        "fields": [
          {
            "python": "id",
            "node": "id",
            "java": "id",
            "type": "string"
          },
          {
            "python": "title",
            "node": "title",
            "java": "title",
            "type": "string"
          },
          {
            "python": "start",
            "node": "start",
            "java": "start",
            "type": "string"
          },
          {
            "python": "end",
            "node": "end",
            "java": "end",
            "type": "string"
          },
          {
            "python": "category_title",
            "node": "categoryTitle",
            "java": "categoryTitle",
            "type": "string"
          },
          {
            "python": "url",
            "node": "url",
            "java": "url",
            "type": "string"
          },
          {
            "python": "description",
            "node": "description",
            "java": "description",
            "type": "string"
          },
          {
            "python": "location",
            "node": "location",
            "java": "location",
            "type": "string"
          }
        ]
      },
      "failure": {
        "mode": "returns-empty-value",
        "emptyValue": "[]",
        "description": {
          "ko": "상류(학교) 실패 시 마지막 캐시 값, 없으면 빈 목록 (dormitory_notices 는 total 0 과 빈 목록의 객체). 예외를 던지지 않음",
          "en": "On upstream failure: the last cached value, else an empty list (dormitory_notices: an object with total 0 and empty lists). Never raises for upstream problems"
        },
        "invalidInput": null
      },
      "cache": {
        "ko": "메서드·인자별 메모리 캐시, 기본 86400초 (cache_ttl_seconds). 같은 인자의 동시 호출은 요청 1건을 공유. 실패 후 캐시가 없으면 60초(failure_cache_seconds) 동안 요청 없이 빈 값. 최대 500항목",
        "en": "In-memory cache per method and arguments, 86400 seconds by default (cache_ttl_seconds). Concurrent calls with the same arguments share one request. After a failure with no cached value, the empty value is returned for 60 seconds (failure_cache_seconds) without a request. At most 500 entries"
      },
      "requestCount": "1",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/data/extracurricular/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/data/extracurricular/"
      }
    },
    {
      "id": "authenticate",
      "group": "auth",
      "requiresLogin": true,
      "summary": {
        "ko": "통합 인증: 학번·비밀번호 확인 + 학생 정보 + 고전독서 + 연락처 (포털 로그인 1회)",
        "en": "Combined login: verifies student id and password, returns student info, classic reading and contact data (one portal login)"
      },
      "names": {
        "python": "authenticate",
        "node": "authenticate",
        "java": [
          "authenticate",
          "authenticateWithRaw"
        ]
      },
      "usage": {
        "python": "authenticate(student_id, password, include_raw=False, include_extra=False)",
        "node": "await authenticate(studentId, password, { includeRaw?, includeExtra? })",
        "java": [
          "authenticate(String studentId, String password)",
          "authenticateWithRaw(String studentId, String password)",
          "authenticate(String studentId, String password, boolean shouldIncludeRaw, boolean shouldIncludeExtra)"
        ]
      },
      "parameters": [
        {
          "name": "student_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학번",
            "en": "Student id"
          },
          "nodeName": "studentId"
        },
        {
          "name": "password",
          "type": "string",
          "required": true,
          "description": {
            "ko": "포털 비밀번호 (저장·로그 금지)",
            "en": "Portal password (never store or log)"
          },
          "nodeName": "password"
        },
        {
          "name": "include_raw",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": {
            "ko": "학교가 준 원문(DHC HTML, SIS JSON) 포함 (디버깅용)",
            "en": "Include the raw school responses (DHC HTML, SIS JSON; debugging)"
          },
          "nodeName": "includeRaw"
        },
        {
          "name": "include_extra",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": {
            "ko": "SIS 나머지 필드를 extra 로 포함",
            "en": "Include remaining SIS fields as extra"
          },
          "nodeName": "includeExtra"
        }
      ],
      "returns": {
        "model": "SejongAuthResult",
        "isList": false,
        "fieldsDocs": "https://cassiiopeia.github.io/pro-sejongpeia/auth/result-fields/"
      },
      "failure": {
        "mode": "raises",
        "description": {
          "ko": "실패 시 SejongAuthError(ErrorCode) 예외 (자바는 SejongAuthException). 틀린 비밀번호는 재시도 없이 즉시 실패",
          "en": "Raises SejongAuthError(ErrorCode) on failure (Java: SejongAuthException). A wrong password fails at once without retry"
        },
        "invalidInput": {
          "ko": "빈 학번이나 빈 비밀번호는 네트워크 호출 전에 INVALID_INPUT",
          "en": "A blank student id or password gives INVALID_INPUT before any network call"
        }
      },
      "requestCount": "portal login once, then one request per step",
      "notes": {
        "ko": "흐름: 포털 로그인 1회 > DHC 학생 정보·고전독서 > 같은 세션으로 SIS 연락처, 포털 메인 상위 소속. DHC 단계가 실패하면 호출 전체 실패, SIS 연락처·포털 메인 단계가 실패해도 호출은 성공하고 그 필드만 null. 모듈 함수 authenticate 는 기본 설정 (10초, 재시도 3회, 인증서 검증). Java: authenticateWithRaw 는 원문 포함, authenticate(학번, 비밀번호, shouldIncludeRaw, shouldIncludeExtra) 는 둘을 골라 포함 (추가 요청 없음)",
        "en": "Flow: one portal login > DHC student info and classic reading > same session for SIS contact data and the portal main parent unit. A failed DHC step fails the whole call; if the SIS contact or portal main step fails the call still succeeds and only those fields are null. The module-level authenticate uses the default settings (10 seconds, 3 retries, certificate check). Java: authenticateWithRaw includes the raw responses, authenticate(studentId, password, shouldIncludeRaw, shouldIncludeExtra) picks either (no extra request)"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/auth/methods/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/auth/methods/"
      }
    },
    {
      "id": "authenticate_dhc",
      "group": "auth",
      "requiresLogin": true,
      "summary": {
        "ko": "DHC 인증: 학생 정보 + 고전독서",
        "en": "DHC login: student info and classic reading"
      },
      "names": {
        "python": "authenticate_dhc",
        "node": "authenticateDhc",
        "java": [
          "authenticateWithDHC",
          "authenticateWithDHCRaw"
        ]
      },
      "usage": {
        "python": "authenticate_dhc(student_id, password, include_raw=False)",
        "node": "await authenticateDhc(studentId, password, { includeRaw? })",
        "java": [
          "authenticateWithDHC(String studentId, String password)",
          "authenticateWithDHCRaw(String studentId, String password)"
        ]
      },
      "parameters": [
        {
          "name": "student_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학번",
            "en": "Student id"
          },
          "nodeName": "studentId"
        },
        {
          "name": "password",
          "type": "string",
          "required": true,
          "description": {
            "ko": "포털 비밀번호 (저장·로그 금지)",
            "en": "Portal password (never store or log)"
          },
          "nodeName": "password"
        },
        {
          "name": "include_raw",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": {
            "ko": "원본 HTML 포함 (디버깅용)",
            "en": "Include the raw HTML (debugging)"
          },
          "nodeName": "includeRaw"
        }
      ],
      "returns": {
        "model": "SejongDhcAuthResult",
        "isList": false,
        "fieldsDocs": "https://cassiiopeia.github.io/pro-sejongpeia/auth/result-fields/"
      },
      "failure": {
        "mode": "raises",
        "description": {
          "ko": "실패 시 SejongAuthError(ErrorCode) 예외 (자바는 SejongAuthException). 틀린 비밀번호는 재시도 없이 즉시 실패",
          "en": "Raises SejongAuthError(ErrorCode) on failure (Java: SejongAuthException). A wrong password fails at once without retry"
        },
        "invalidInput": {
          "ko": "빈 학번이나 빈 비밀번호는 INVALID_INPUT",
          "en": "A blank student id or password gives INVALID_INPUT"
        }
      },
      "requestCount": "portal login once, then one request per step",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/auth/methods/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/auth/methods/"
      }
    },
    {
      "id": "authenticate_sis",
      "group": "auth",
      "requiresLogin": true,
      "summary": {
        "ko": "SIS 인증: 학생 정보 + 연락처 + 학교 제공 코드 (학년·상태는 빈 문자열)",
        "en": "SIS login: student info, contact data and school codes (grade and status are empty strings)"
      },
      "names": {
        "python": "authenticate_sis",
        "node": "authenticateSis",
        "java": [
          "authenticateWithSIS",
          "authenticateWithSISRaw"
        ]
      },
      "usage": {
        "python": "authenticate_sis(student_id, password, include_raw=False, include_extra=False)",
        "node": "await authenticateSis(studentId, password, { includeRaw?, includeExtra? })",
        "java": [
          "authenticateWithSIS(String studentId, String password)",
          "authenticateWithSIS(String studentId, String password, boolean shouldIncludeRaw, boolean shouldIncludeExtra)",
          "authenticateWithSISRaw(String studentId, String password)"
        ]
      },
      "parameters": [
        {
          "name": "student_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학번",
            "en": "Student id"
          },
          "nodeName": "studentId"
        },
        {
          "name": "password",
          "type": "string",
          "required": true,
          "description": {
            "ko": "포털 비밀번호 (저장·로그 금지)",
            "en": "Portal password (never store or log)"
          },
          "nodeName": "password"
        },
        {
          "name": "include_raw",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": {
            "ko": "원본 JSON 포함 (디버깅용)",
            "en": "Include the raw JSON (debugging)"
          },
          "nodeName": "includeRaw"
        },
        {
          "name": "include_extra",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": {
            "ko": "나머지 필드를 extra 로 포함",
            "en": "Include remaining fields as extra"
          },
          "nodeName": "includeExtra"
        }
      ],
      "returns": {
        "model": "SejongSisAuthResult",
        "isList": false,
        "fieldsDocs": "https://cassiiopeia.github.io/pro-sejongpeia/auth/result-fields/"
      },
      "failure": {
        "mode": "raises",
        "description": {
          "ko": "실패 시 SejongAuthError(ErrorCode) 예외 (자바는 SejongAuthException). 틀린 비밀번호는 재시도 없이 즉시 실패",
          "en": "Raises SejongAuthError(ErrorCode) on failure (Java: SejongAuthException). A wrong password fails at once without retry"
        },
        "invalidInput": {
          "ko": "빈 학번이나 빈 비밀번호는 INVALID_INPUT",
          "en": "A blank student id or password gives INVALID_INPUT"
        }
      },
      "requestCount": "portal login once, then one request per step",
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/auth/methods/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/auth/methods/"
      }
    },
    {
      "id": "fetch_sis_business_periods",
      "group": "auth",
      "requiresLogin": true,
      "summary": {
        "ko": "SIS 학사 업무 기간 (수강신청 등 업무별 허용 기간)",
        "en": "SIS business periods (allowed periods per task such as course registration)"
      },
      "names": {
        "python": "fetch_sis_business_periods",
        "node": "fetchSisBusinessPeriods",
        "java": [
          "fetchSisBusinessPeriods"
        ]
      },
      "usage": {
        "python": "fetch_sis_business_periods(student_id, password, year, month=\"\")",
        "node": "await fetchSisBusinessPeriods(studentId, password, { year, month? })",
        "java": [
          "fetchSisBusinessPeriods(String studentId, String password, String year, String month)"
        ]
      },
      "parameters": [
        {
          "name": "student_id",
          "type": "string",
          "required": true,
          "description": {
            "ko": "학번",
            "en": "Student id"
          },
          "nodeName": "studentId"
        },
        {
          "name": "password",
          "type": "string",
          "required": true,
          "description": {
            "ko": "포털 비밀번호 (저장·로그 금지)",
            "en": "Portal password (never store or log)"
          },
          "nodeName": "password"
        },
        {
          "name": "year",
          "type": "string",
          "required": true,
          "description": {
            "ko": "연도 4자리 (숫자도 가능)",
            "en": "Four-digit year (a number is accepted)"
          },
          "nodeName": "year"
        },
        {
          "name": "month",
          "type": "string",
          "required": false,
          "default": "",
          "description": {
            "ko": "월 1~12, 비우면 연간 전체",
            "en": "Month 1 to 12; empty means the whole year"
          },
          "nodeName": "month"
        }
      ],
      "returns": {
        "model": "SisBusinessPeriod",
        "isList": true,
        "fieldsDocs": "https://cassiiopeia.github.io/pro-sejongpeia/auth/result-fields/"
      },
      "failure": {
        "mode": "raises",
        "description": {
          "ko": "실패 시 SejongAuthError(ErrorCode) 예외 (자바는 SejongAuthException). 틀린 비밀번호는 재시도 없이 즉시 실패",
          "en": "Raises SejongAuthError(ErrorCode) on failure (Java: SejongAuthException). A wrong password fails at once without retry"
        },
        "invalidInput": {
          "ko": "연도가 4자리 숫자가 아니거나 월이 1~12·빈 값이 아니면 INVALID_INPUT",
          "en": "INVALID_INPUT when the year is not 4 digits or the month is not 1 to 12 or empty"
        }
      },
      "requestCount": "portal login once, then one request per step",
      "notes": {
        "ko": "흐름: 포털 로그인 > SIS 사용자 정보 > 메뉴 목록 > 화면 열기 > 목록. 요청 실패는 재시도 없이 예외, 세션 종료·조회 실패도 SejongAuthError",
        "en": "Flow: portal login > SIS user info > menu list > open the screen > list. A failed request raises without retry; an ended session or a failed lookup also raises SejongAuthError"
      },
      "docs": {
        "ko": "https://cassiiopeia.github.io/pro-sejongpeia/auth/business-periods/",
        "en": "https://cassiiopeia.github.io/pro-sejongpeia/en/auth/business-periods/"
      }
    }
  ],
  "models": {
    "OrganizationCategory": [
      {
        "python": "code",
        "node": "code",
        "java": "code",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "name_en",
        "node": "nameEn",
        "java": "nameEn",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "Term": [
      {
        "python": "year",
        "node": "year",
        "java": "year",
        "type": "string"
      },
      {
        "python": "semester_code",
        "node": "semesterCode",
        "java": "semesterCode",
        "type": "string"
      },
      {
        "python": "code",
        "node": "code",
        "java": "code",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "Department": [
      {
        "python": "code",
        "node": "code",
        "java": "code",
        "type": "string"
      },
      {
        "python": "level",
        "node": "level",
        "java": "level",
        "type": "string"
      },
      {
        "python": "college_code",
        "node": "collegeCode",
        "java": "collegeCode",
        "type": "string"
      },
      {
        "python": "college_name",
        "node": "collegeName",
        "java": "collegeName",
        "type": "string"
      },
      {
        "python": "unit_code",
        "node": "unitCode",
        "java": "unitCode",
        "type": "string"
      },
      {
        "python": "unit_name",
        "node": "unitName",
        "java": "unitName",
        "type": "string"
      },
      {
        "python": "major_code",
        "node": "majorCode",
        "java": "majorCode",
        "type": "string"
      },
      {
        "python": "major_name",
        "node": "majorName",
        "java": "majorName",
        "type": "string"
      },
      {
        "python": "name_en",
        "node": "nameEn",
        "java": "nameEn",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "CourseType": [
      {
        "python": "code",
        "node": "code",
        "java": "code",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "category_code",
        "node": "categoryCode",
        "java": "categoryCode",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "SelectiveDomain": [
      {
        "python": "code",
        "node": "code",
        "java": "code",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "name_en",
        "node": "nameEn",
        "java": "nameEn",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "Lecture": [
      {
        "python": "course_number",
        "node": "courseNumber",
        "java": "courseNumber",
        "type": "string"
      },
      {
        "python": "section",
        "node": "section",
        "java": "section",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "course_type_code",
        "node": "courseTypeCode",
        "java": "courseTypeCode",
        "type": "string"
      },
      {
        "python": "course_type_name",
        "node": "courseTypeName",
        "java": "courseTypeName",
        "type": "string"
      },
      {
        "python": "domain_code",
        "node": "domainCode",
        "java": "domainCode",
        "type": "string"
      },
      {
        "python": "domain_name",
        "node": "domainName",
        "java": "domainName",
        "type": "string"
      },
      {
        "python": "credits",
        "node": "credits",
        "java": "credits",
        "type": "string"
      },
      {
        "python": "hours",
        "node": "hours",
        "java": "hours",
        "type": "string"
      },
      {
        "python": "total_hours",
        "node": "totalHours",
        "java": "totalHours",
        "type": "string"
      },
      {
        "python": "schedule",
        "node": "schedule",
        "java": "schedule",
        "type": "string"
      },
      {
        "python": "room",
        "node": "room",
        "java": "room",
        "type": "string"
      },
      {
        "python": "instructor",
        "node": "instructor",
        "java": "instructor",
        "type": "string"
      },
      {
        "python": "grade_level",
        "node": "gradeLevel",
        "java": "gradeLevel",
        "type": "string"
      },
      {
        "python": "language_code",
        "node": "languageCode",
        "java": "languageCode",
        "type": "string"
      },
      {
        "python": "language_name",
        "node": "languageName",
        "java": "languageName",
        "type": "string"
      },
      {
        "python": "department_code",
        "node": "departmentCode",
        "java": "departmentCode",
        "type": "string"
      },
      {
        "python": "department_name",
        "node": "departmentName",
        "java": "departmentName",
        "type": "string"
      },
      {
        "python": "managing_department",
        "node": "managingDepartment",
        "java": "managingDepartment",
        "type": "string"
      },
      {
        "python": "remark",
        "node": "remark",
        "java": "remark",
        "type": "string"
      },
      {
        "python": "year",
        "node": "year",
        "java": "year",
        "type": "string"
      },
      {
        "python": "semester_code",
        "node": "semesterCode",
        "java": "semesterCode",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "CurriculumCourse": [
      {
        "python": "department_code",
        "node": "departmentCode",
        "java": "departmentCode",
        "type": "string"
      },
      {
        "python": "department_name",
        "node": "departmentName",
        "java": "departmentName",
        "type": "string"
      },
      {
        "python": "category_code",
        "node": "categoryCode",
        "java": "categoryCode",
        "type": "string"
      },
      {
        "python": "year",
        "node": "year",
        "java": "year",
        "type": "string"
      },
      {
        "python": "course_number",
        "node": "courseNumber",
        "java": "courseNumber",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "course_type_code",
        "node": "courseTypeCode",
        "java": "courseTypeCode",
        "type": "string"
      },
      {
        "python": "course_type_name",
        "node": "courseTypeName",
        "java": "courseTypeName",
        "type": "string"
      },
      {
        "python": "credits",
        "node": "credits",
        "java": "credits",
        "type": "string"
      },
      {
        "python": "lecture_hours",
        "node": "lectureHours",
        "java": "lectureHours",
        "type": "string"
      },
      {
        "python": "practice_hours",
        "node": "practiceHours",
        "java": "practiceHours",
        "type": "string"
      },
      {
        "python": "total_hours",
        "node": "totalHours",
        "java": "totalHours",
        "type": "string"
      },
      {
        "python": "grade_level",
        "node": "gradeLevel",
        "java": "gradeLevel",
        "type": "string"
      },
      {
        "python": "semester_code",
        "node": "semesterCode",
        "java": "semesterCode",
        "type": "string"
      },
      {
        "python": "semester_name",
        "node": "semesterName",
        "java": "semesterName",
        "type": "string"
      },
      {
        "python": "overview",
        "node": "overview",
        "java": "overview",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "CalendarEvent": [
      {
        "python": "year",
        "node": "year",
        "java": "year",
        "type": "string"
      },
      {
        "python": "month",
        "node": "month",
        "java": "month",
        "type": "string"
      },
      {
        "python": "category_code",
        "node": "categoryCode",
        "java": "categoryCode",
        "type": "string"
      },
      {
        "python": "category_name",
        "node": "categoryName",
        "java": "categoryName",
        "type": "string"
      },
      {
        "python": "title",
        "node": "title",
        "java": "title",
        "type": "string"
      },
      {
        "python": "title_en",
        "node": "titleEn",
        "java": "titleEn",
        "type": "string"
      },
      {
        "python": "start_date",
        "node": "startDate",
        "java": "startDate",
        "type": "string"
      },
      {
        "python": "end_date",
        "node": "endDate",
        "java": "endDate",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "DormitoryMenuDay": [
      {
        "python": "date",
        "node": "date",
        "java": "date",
        "type": "string"
      },
      {
        "python": "breakfast",
        "node": "breakfast",
        "java": "breakfast",
        "type": "string"
      },
      {
        "python": "lunch",
        "node": "lunch",
        "java": "lunch",
        "type": "string"
      },
      {
        "python": "dinner",
        "node": "dinner",
        "java": "dinner",
        "type": "string"
      },
      {
        "python": "alternative",
        "node": "alternative",
        "java": "alternative",
        "type": "string"
      }
    ],
    "DormitoryNotice": [
      {
        "python": "id",
        "node": "id",
        "java": "id",
        "type": "string"
      },
      {
        "python": "title",
        "node": "title",
        "java": "title",
        "type": "string"
      },
      {
        "python": "date",
        "node": "date",
        "java": "date",
        "type": "string"
      },
      {
        "python": "views",
        "node": "views",
        "java": "views",
        "type": "integer"
      },
      {
        "python": "file_name",
        "node": "fileName",
        "java": "fileName",
        "type": "string"
      }
    ],
    "DormitoryNotices": [
      {
        "python": "total",
        "node": "total",
        "java": "total",
        "type": "integer"
      },
      {
        "python": "pinned",
        "node": "pinned",
        "java": "pinned",
        "type": "DormitoryNotice[]"
      },
      {
        "python": "items",
        "node": "items",
        "java": "items",
        "type": "DormitoryNotice[]"
      }
    ],
    "CafeteriaMenuItem": [
      {
        "python": "building_name",
        "node": "buildingName",
        "java": "buildingName",
        "type": "string"
      },
      {
        "python": "location",
        "node": "location",
        "java": "location",
        "type": "string"
      },
      {
        "python": "place_id",
        "node": "placeId",
        "java": "placeId",
        "type": "string"
      },
      {
        "python": "place_name",
        "node": "placeName",
        "java": "placeName",
        "type": "string"
      },
      {
        "python": "date",
        "node": "date",
        "java": "date",
        "type": "string"
      },
      {
        "python": "day",
        "node": "day",
        "java": "day",
        "type": "string"
      },
      {
        "python": "meal_type_id",
        "node": "mealTypeId",
        "java": "mealTypeId",
        "type": "string"
      },
      {
        "python": "meal_name",
        "node": "mealName",
        "java": "mealName",
        "type": "string"
      },
      {
        "python": "menu_name",
        "node": "menuName",
        "java": "menuName",
        "type": "string"
      },
      {
        "python": "price",
        "node": "price",
        "java": "price",
        "type": "string"
      }
    ],
    "CafeteriaPlace": [
      {
        "python": "place_id",
        "node": "placeId",
        "java": "placeId",
        "type": "string"
      },
      {
        "python": "place_name",
        "node": "placeName",
        "java": "placeName",
        "type": "string"
      },
      {
        "python": "building_name",
        "node": "buildingName",
        "java": "buildingName",
        "type": "string"
      },
      {
        "python": "location",
        "node": "location",
        "java": "location",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "CampusPlace": [
      {
        "python": "id",
        "node": "id",
        "java": "id",
        "type": "string"
      },
      {
        "python": "name",
        "node": "name",
        "java": "name",
        "type": "string"
      },
      {
        "python": "name_en",
        "node": "nameEn",
        "java": "nameEn",
        "type": "string"
      },
      {
        "python": "place_type",
        "node": "placeType",
        "java": "placeType",
        "type": "string"
      },
      {
        "python": "category",
        "node": "category",
        "java": "category",
        "type": "string"
      },
      {
        "python": "latitude",
        "node": "latitude",
        "java": "latitude",
        "type": "number"
      },
      {
        "python": "longitude",
        "node": "longitude",
        "java": "longitude",
        "type": "number"
      },
      {
        "python": "info",
        "node": "info",
        "java": "info",
        "type": "string"
      },
      {
        "python": "phone",
        "node": "phone",
        "java": "phone",
        "type": "string"
      },
      {
        "python": "description",
        "node": "description",
        "java": "description",
        "type": "string"
      },
      {
        "python": "extra",
        "node": "extra",
        "java": "extra",
        "type": "object<string,string>"
      }
    ],
    "ExtracurricularEvent": [
      {
        "python": "id",
        "node": "id",
        "java": "id",
        "type": "string"
      },
      {
        "python": "title",
        "node": "title",
        "java": "title",
        "type": "string"
      },
      {
        "python": "start",
        "node": "start",
        "java": "start",
        "type": "string"
      },
      {
        "python": "end",
        "node": "end",
        "java": "end",
        "type": "string"
      },
      {
        "python": "category_title",
        "node": "categoryTitle",
        "java": "categoryTitle",
        "type": "string"
      },
      {
        "python": "url",
        "node": "url",
        "java": "url",
        "type": "string"
      },
      {
        "python": "description",
        "node": "description",
        "java": "description",
        "type": "string"
      },
      {
        "python": "location",
        "node": "location",
        "java": "location",
        "type": "string"
      }
    ]
  },
  "modelNaming": {
    "ko": "Python 은 snake_case, Node.js 는 camelCase 필드. Java 모델은 같은 camelCase 이름의 getter (getCourseNumber())",
    "en": "Python uses snake_case fields, Node.js camelCase fields. Java models expose the same camelCase names as getters (getCourseNumber())"
  }
}
