From 572e7ba10e5564cd406bdb349cc02b03b699851b Mon Sep 17 00:00:00 2001 From: b0nsu <125778250+b0nsu@users.noreply.github.com> Date: Tue, 5 May 2026 21:26:10 +0900 Subject: [PATCH 1/2] =?UTF-8?q?chore(api):=20MAT-542=20OpenAPI=20schema=20?= =?UTF-8?q?=EB=8F=99=EA=B8=B0=ED=99=94=20=E2=80=94=20dataJson=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ScrapHandwritingUpdateRequest / ScrapHandwritingResp 양쪽에 dataJson?: string 추가, data 가 optional 로 완화. 그 외 도메인의 schema 변경분 동시 반영 (서버 develop OpenAPI 기준 누적분). Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/native/src/types/api/schema.d.ts | 3079 +++++++++++++++++++++---- 1 file changed, 2596 insertions(+), 483 deletions(-) diff --git a/apps/native/src/types/api/schema.d.ts b/apps/native/src/types/api/schema.d.ts index 673e15b12..5812cbf09 100644 --- a/apps/native/src/types/api/schema.d.ts +++ b/apps/native/src/types/api/schema.d.ts @@ -81,6 +81,25 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/study/problem/{publishId}/{problemId}/handwriting': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 필기 데이터 조회 */ + get: operations['getHandwriting']; + /** 필기 데이터 저장/수정 */ + put: operations['updateHandwriting']; + post?: never; + /** 필기 데이터 삭제 */ + delete: operations['deleteHandwriting']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/scrap/{scrapId}': { parameters: { query?: never; @@ -157,12 +176,12 @@ export interface paths { cookie?: never; }; /** 필기 데이터 조회 */ - get: operations['getHandwriting']; + get: operations['getHandwriting_1']; /** 필기 데이터 저장/수정 */ - put: operations['updateHandwriting']; + put: operations['updateHandwriting_1']; post?: never; /** 필기 데이터 삭제 */ - delete: operations['deleteHandwriting']; + delete: operations['deleteHandwriting_1']; options?: never; head?: never; patch?: never; @@ -401,6 +420,24 @@ export interface paths { patch?: never; trace?: never; }; + '/api/admin/role/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 역할 수정 */ + put: operations['update_4']; + post?: never; + /** 역할 삭제 */ + delete: operations['delete_2']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/admin/qna/{qnaId}/status': { parameters: { query?: never; @@ -465,10 +502,10 @@ export interface paths { /** 상세 조회 */ get: operations['getProblemSet']; /** 수정 */ - put: operations['update_4']; + put: operations['update_5']; post?: never; /** 삭제 */ - delete: operations['delete_2']; + delete: operations['delete_3']; options?: never; head?: never; patch?: never; @@ -500,10 +537,27 @@ export interface paths { }; get?: never; /** 수정 */ - put: operations['update_5']; + put: operations['update_6']; post?: never; /** 삭제 */ - delete: operations['delete_3']; + delete: operations['delete_4']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/pointing/bubble/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 버블 수정 */ + put: operations['update_7']; + post?: never; + delete?: never; options?: never; head?: never; patch?: never; @@ -518,10 +572,28 @@ export interface paths { }; get?: never; /** 수정 */ - put: operations['update_6']; + put: operations['update_8']; post?: never; /** 삭제 */ - delete: operations['delete_4']; + delete: operations['delete_5']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/mock-exam/types/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 모의고사 타입 수정 */ + put: operations['updateType']; + post?: never; + /** 모의고사 타입 삭제 */ + delete: operations['deleteType']; options?: never; head?: never; patch?: never; @@ -537,10 +609,28 @@ export interface paths { /** 학생 진단 상세보기 */ get: operations['getById_1']; /** 수정 */ - put: operations['update_7']; + put: operations['update_9']; post?: never; /** 삭제 */ - delete: operations['delete_5']; + delete: operations['delete_6']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/daily-comments/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 데일리 코멘트 수정 */ + put: operations['update_10']; + post?: never; + /** 데일리 코멘트 삭제 */ + delete: operations['delete_7']; options?: never; head?: never; patch?: never; @@ -555,10 +645,118 @@ export interface paths { }; get?: never; /** 개념태그 수정 */ - put: operations['update_8']; + put: operations['update_11']; post?: never; /** 개념태그 삭제 */ - delete: operations['delete_6']; + delete: operations['delete_8']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/node/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 노드 수정 */ + put: operations['updateNode']; + post?: never; + /** 노드 삭제 */ + delete: operations['deleteNode']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/node-type/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 노드 타입 수정 */ + put: operations['updateNodeType']; + post?: never; + /** 노드 타입 삭제 */ + delete: operations['deleteNodeType']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/edge/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 엣지 수정 */ + put: operations['updateEdge']; + post?: never; + /** 엣지 삭제 */ + delete: operations['deleteEdge']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/edge-type/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 엣지 타입 수정 */ + put: operations['updateEdgeType']; + post?: never; + /** 엣지 타입 삭제 */ + delete: operations['deleteEdgeType']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/action-edge/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 액션 엣지 수정 */ + put: operations['updateActionEdge']; + post?: never; + /** 액션 엣지 삭제 */ + delete: operations['deleteActionEdge']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/action-edge-type/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** 액션 엣지 타입 수정 */ + put: operations['updateActionEdgeType']; + post?: never; + /** 액션 엣지 타입 삭제 */ + delete: operations['deleteActionEdgeType']; options?: never; head?: never; patch?: never; @@ -706,6 +904,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/study/submit/bubble/question': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** 버블 ? 버튼 누름 제출 */ + post: operations['recordBubbleQuestion']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/study/submit/answer': { parameters: { query?: never; @@ -939,6 +1154,26 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/oauth/native': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Native OAuth 로그인 + * @description 클라이언트에서 직접 받은 OAuth 토큰으로 로그인합니다. Kakao는 access_token, Google/Apple은 id_token을 전달합니다. + */ + post: operations['nativeLogin']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/notification/read/{notificationId}': { parameters: { query?: never; @@ -973,6 +1208,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/mock-exam': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** 모의고사 정오답/학습 고민 제출 */ + post: operations['submit_1']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/me/push/token': { parameters: { query?: never; @@ -1402,6 +1654,24 @@ export interface paths { patch?: never; trace?: never; }; + '/api/admin/role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 역할 목록 조회 */ + get: operations['findAll']; + put?: never; + /** 역할 생성 */ + post: operations['create_4']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/admin/qna/chat': { parameters: { query?: never; @@ -1430,7 +1700,7 @@ export interface paths { get: operations['search_1']; put?: never; /** 생성 */ - post: operations['create_4']; + post: operations['create_5']; delete?: never; options?: never; head?: never; @@ -1502,7 +1772,7 @@ export interface paths { get: operations['search_3']; put?: never; /** 생성 */ - post: operations['create_5']; + post: operations['create_6']; delete?: never; options?: never; head?: never; @@ -1520,7 +1790,7 @@ export interface paths { get: operations['search_4']; put?: never; /** 생성 */ - post: operations['create_6']; + post: operations['create_7']; delete?: never; options?: never; head?: never; @@ -1574,60 +1844,222 @@ export interface paths { get: operations['getsAll_1']; put?: never; /** 생성 */ - post: operations['create_7']; + post: operations['create_8']; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - '/api/admin/fcm/test': { + '/api/admin/mock-exam/types': { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - get?: never; + /** 모의고사 타입 전체 조회 */ + get: operations['getAllTypes']; put?: never; - /** 특정 토큰으로 FCM 푸시 테스트 발송 */ - post: operations['sendTestPush']; + /** 모의고사 타입 생성 */ + post: operations['createType']; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - '/api/admin/diagnosis': { + '/api/admin/menu': { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** 학생 진단 가져오기 */ - get: operations['gets_1']; + /** 메뉴 목록 조회 */ + get: operations['findAll_1']; put?: never; - /** 생성 */ - post: operations['create_8']; + /** 메뉴 추가 */ + post: operations['create_9']; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - '/api/admin/concept': { + '/api/admin/fcm/test': { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** 개념 태그 검색 */ - get: operations['search_5']; + get?: never; put?: never; - /** 개념태그 생성 */ - post: operations['create_9']; + /** 특정 토큰으로 FCM 푸시 테스트 발송 */ + post: operations['sendTestPush']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/diagnosis': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 학생 진단 가져오기 */ + get: operations['gets_1']; + put?: never; + /** 생성 */ + post: operations['create_10']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/daily-comments': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 학생별 특정 일자 데일리 코멘트 조회 */ + get: operations['getByStudentAndDate']; + put?: never; + /** 데일리 코멘트 생성 또는 수정 */ + post: operations['upsert']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 개념 태그 검색 */ + get: operations['search_5']; + put?: never; + /** 개념태그 생성 */ + post: operations['create_11']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/node': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 노드 목록 조회 */ + get: operations['getNodes']; + put?: never; + /** 노드 생성 */ + post: operations['createNode']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/node-type': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 노드 타입 목록 조회 */ + get: operations['getNodeTypes']; + put?: never; + /** 노드 타입 생성 */ + post: operations['createNodeType']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/edge': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 엣지 목록 조회 */ + get: operations['getEdges']; + put?: never; + /** 엣지 생성 */ + post: operations['createEdge']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/edge-type': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 엣지 타입 목록 조회 */ + get: operations['getEdgeTypes']; + put?: never; + /** 엣지 타입 생성 */ + post: operations['createEdgeType']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/action-edge': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 액션 엣지 목록 조회 */ + get: operations['getActionEdges']; + put?: never; + /** 액션 엣지 생성 */ + post: operations['createActionEdge']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/concept/graph/action-edge-type': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 액션 엣지 타입 목록 조회 */ + get: operations['getActionEdgeTypes']; + put?: never; + /** 액션 엣지 타입 생성 */ + post: operations['createActionEdgeType']; delete?: never; options?: never; head?: never; @@ -1686,6 +2118,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/admin/user/{id}/role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** 관리자에 역할 할당 (roleId=null이면 슈퍼 관리자 전환) */ + patch: operations['assignRole']; + trace?: never; + }; '/your-redirect-url': { parameters: { query?: never; @@ -2300,6 +2749,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/mock-exam/current-type': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 현재 활성 모의고사 타입 조회 */ + get: operations['getCurrentType']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/diagnosis': { parameters: { query?: never; @@ -2351,6 +2817,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/student/daily-comments': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 특정 일자 데일리 코멘트 조회 */ + get: operations['getByDate']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/student/auth/email/exists': { parameters: { query?: never; @@ -2421,22 +2904,6 @@ export interface paths { patch?: never; trace?: never; }; - '/api/exception/throw': { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: operations['throwException']; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; '/api/common/auth/refresh': { parameters: { query?: never; @@ -2517,7 +2984,7 @@ export interface paths { put?: never; post?: never; /** 삭제 */ - delete: operations['delete_7']; + delete: operations['delete_9']; options?: never; head?: never; patch?: never; @@ -2574,6 +3041,23 @@ export interface paths { patch?: never; trace?: never; }; + '/api/admin/mock-exam': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** 학생별 모의고사 정오답/학습 고민 조회 */ + get: operations['getByStudent']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/api/admin/fcm/status': { parameters: { query?: never; @@ -2735,7 +3219,7 @@ export interface paths { put?: never; post?: never; /** 삭제 */ - delete: operations['delete_8']; + delete: operations['delete_10']; options?: never; head?: never; patch?: never; @@ -2752,7 +3236,7 @@ export interface paths { put?: never; post?: never; /** 선생님 삭제 */ - delete: operations['delete_9']; + delete: operations['delete_11']; options?: never; head?: never; patch?: never; @@ -2974,6 +3458,34 @@ export interface components { /** @description 마케팅 알림 허용 여부 (이벤트 및 업데이트 관련 알림) */ isAllowMarketingPush?: boolean; }; + StudyHandwritingUpdateRequest: { + /** @description 필기 데이터 (Base64 인코딩) */ + data?: string; + /** @description 필기 데이터 (JSON) */ + dataJson?: string; + }; + /** @description 학습 필기 데이터 응답 */ + StudyHandwritingResp: { + /** + * Format: int64 + * @description 발행 ID + */ + publishId: number; + /** + * Format: int64 + * @description 문제 ID + */ + problemId: number; + /** @description 필기 데이터 (Base64 인코딩) */ + data?: string; + /** @description 필기 데이터 (JSON) */ + dataJson?: string; + /** + * Format: date-time + * @description 필기 데이터 수정일시 (필기 없으면 null) + */ + updatedAt?: string; + }; ScrapUpdateRequest: { /** * Format: int64 @@ -3004,6 +3516,19 @@ export interface components { name: string; category: components['schemas']['ConceptCategoryResp']; }; + PointingBubbleResp: { + /** Format: int64 */ + id: number; + /** Format: int32 */ + no: number; + contentJson: string; + extendContent?: string; + /** Format: int64 */ + actionNodeId?: number; + actionNodeName?: string; + /** @description ? 버튼 눌렀는지 여부 (학생 컨텍스트에서만 설정됨) */ + isQuestionPressed?: boolean; + }; /** @description 포인팅 목록 */ PointingResp: { /** Format: int64 */ @@ -3012,6 +3537,7 @@ export interface components { no: number; questionContent: string; commentContent: string; + bubbles?: components['schemas']['PointingBubbleResp'][]; concepts: components['schemas']['ConceptResp'][]; }; PracticeTestResp: { @@ -3173,7 +3699,9 @@ export interface components { }; ScrapHandwritingUpdateRequest: { /** @description 필기 데이터 (Base64 인코딩) */ - data: string; + data?: string; + /** @description 필기 데이터 (JSON) */ + dataJson?: string; }; /** @description 필기 데이터 응답 */ ScrapHandwritingResp: { @@ -3183,7 +3711,9 @@ export interface components { */ scrapId: number; /** @description 필기 데이터 (Base64 인코딩) */ - data: string; + data?: string; + /** @description 필기 데이터 (JSON) */ + dataJson?: string; /** * Format: date-time * @description 필기 데이터 수정일시 (필기 없으면 null) @@ -3220,6 +3750,7 @@ export interface components { targetFolderId?: number; }; ListRespScrapDetailResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['ScrapDetailResp'][]; @@ -3316,6 +3847,20 @@ export interface components { TeacherStudentAssignReq: { students: number[]; }; + AdminRoleUpdateRequest: { + name: string; + menuIds: number[]; + }; + BubbleRequest: { + /** Format: int64 */ + id?: number; + /** Format: int32 */ + no?: number; + contentJson?: string; + extendContent?: string; + /** Format: int64 */ + actionNodeId?: number; + }; PointingUpdateRequest: { /** Format: int64 */ id?: number; @@ -3323,6 +3868,7 @@ export interface components { no?: number; questionContent?: string; commentContent?: string; + bubbles?: components['schemas']['BubbleRequest'][]; concepts?: number[]; }; ProblemUpdateRequest: { @@ -3415,7 +3961,7 @@ export interface components { firstProblem: components['schemas']['ProblemMetaResp']; problems: components['schemas']['ProblemSetItemResp'][]; }; - Request: { + PracticeTestUpdateRequest: { /** Format: int32 */ year: number; /** Format: int32 */ @@ -3424,25 +3970,178 @@ export interface components { grade: number; name: string; }; - DiagnosisUpdateReq: { - content?: string; - }; - DiagnosisResp: { - /** Format: int64 */ - id: number; + PointingBubbleUpdateRequest: { + /** Format: int32 */ + no?: number; + contentJson?: string; + extendContent?: string; /** Format: int64 */ - studentId?: number; - /** Format: date-time */ - createdAt?: string; - content?: string; + actionNodeId?: number; }; - ConceptUpdateRequest: { - name: string; - /** Format: int64 */ - categoryId: number; + MockExamTypeUpdateRequest: { + displayName?: string; + /** Format: date */ + startDate?: string; + /** Format: date */ + endDate?: string; }; - ConceptCategoryUpdateRequest: { - name: string; + MockExamTypeResp: { + /** Format: int64 */ + id: number; + /** + * @description /api/student/mock-exam 제출 요청의 type에 그대로 넣는 값 + * @example 2026-06 + */ + type?: string; + /** + * @description 모의고사 타입 코드. 학생 제출 요청의 type과 동일한 값 + * @example 2026-06 + */ + code?: string; + /** + * @description 화면 표시용 모의고사 타입 이름 + * @example 2026년 6월 모의고사 + */ + displayName?: string; + /** + * Format: date + * @description 해당 타입 활성 시작일 + * @example 2026-06-01 + */ + startDate?: string; + /** + * Format: date + * @description 해당 타입 활성 종료일 + * @example 2026-06-30 + */ + endDate?: string; + }; + DiagnosisUpdateReq: { + content?: string; + }; + DiagnosisResp: { + /** Format: int64 */ + id: number; + /** Format: int64 */ + studentId?: number; + /** Format: date-time */ + createdAt?: string; + content?: string; + }; + UpdateRequest: { + /** + * @description 코멘트 내용 + * @example 수정된 코멘트입니다. + */ + contentJson?: string; + }; + AdminSummary: { + /** Format: int64 */ + id?: number; + name?: string; + }; + DailyCommentResp: { + /** Format: int64 */ + id?: number; + author?: components['schemas']['AdminSummary']; + contentJson?: string; + /** Format: date */ + commentDate?: string; + /** Format: date-time */ + expiryAt?: string; + }; + ConceptUpdateRequest: { + name: string; + /** Format: int64 */ + categoryId: number; + }; + ConceptNodeUpdateRequest: { + name: string; + /** Format: int64 */ + nodeTypeId: number; + description?: string; + payload?: { + [key: string]: Record; + }; + }; + ConceptNodeResp: { + /** Format: int64 */ + id?: number; + name?: string; + nodeType?: components['schemas']['NodeTypeCodeResp']; + description?: string; + payload?: { + [key: string]: Record; + }; + }; + NodeTypeCodeResp: { + /** Format: int64 */ + id?: number; + code?: string; + label?: string; + description?: string; + }; + NodeTypeCodeUpdateRequest: { + code: string; + label: string; + description?: string; + }; + ConceptEdgeUpdateRequest: { + /** Format: int64 */ + fromNodeId: number; + /** Format: int64 */ + edgeTypeId: number; + /** Format: int64 */ + toNodeId: number; + }; + ConceptEdgeResp: { + /** Format: int64 */ + id?: number; + fromNode?: components['schemas']['ConceptNodeResp']; + edgeType?: components['schemas']['EdgeTypeCodeResp']; + toNode?: components['schemas']['ConceptNodeResp']; + }; + EdgeTypeCodeResp: { + /** Format: int64 */ + id?: number; + code?: string; + label?: string; + description?: string; + }; + EdgeTypeCodeUpdateRequest: { + code: string; + label: string; + description?: string; + }; + ConceptActionEdgeUpdateRequest: { + /** Format: int64 */ + actionNodeId: number; + /** Format: int64 */ + roleId: number; + /** Format: int64 */ + conceptNodeId: number; + }; + ActionEdgeTypeCodeResp: { + /** Format: int64 */ + id?: number; + code?: string; + label?: string; + description?: string; + }; + ConceptActionEdgeResp: { + /** Format: int64 */ + id?: number; + actionNode?: components['schemas']['ConceptNodeResp']; + role?: components['schemas']['ActionEdgeTypeCodeResp']; + conceptNode?: components['schemas']['ConceptNodeResp']; + }; + ActionEdgeTypeCodeUpdateRequest: { + code: string; + label: string; + description?: string; + }; + ConceptCategoryUpdateRequest: { + name: string; }; ChatCreateRequest: { /** Format: int64 */ @@ -3511,6 +4210,18 @@ export interface components { */ responseTimeMs?: number; }; + PointingBubbleQuestionRequest: { + /** Format: int64 */ + bubbleId: number; + /** + * Format: int64 + * @description 발행(숙제) ID + */ + publishId?: number; + }; + PointingBubbleQuestionResponse: { + extendContent?: string; + }; SubmissionRequest: { /** Format: int64 */ publishId: number; @@ -3720,6 +4431,80 @@ export interface components { id: number; isExist: boolean; }; + /** @description Native OAuth 로그인 요청 */ + NativeOAuthReq: { + /** + * @description OAuth 제공자 + * @example KAKAO + * @enum {string} + */ + provider: 'KAKAO' | 'GOOGLE' | 'APPLE'; + /** @description OAuth 토큰 (Kakao: access_token, Google/Apple: id_token) */ + token: string; + }; + /** @description Native OAuth 로그인 응답 */ + NativeOAuthResp: { + /** @description 로그인 성공 여부 */ + success?: boolean; + /** @description 응답 메시지 */ + message?: string; + /** @description JWT Access Token */ + accessToken?: string; + /** @description JWT Refresh Token */ + refreshToken?: string; + user?: components['schemas']['NativeOAuthResp.StudentInfo']; + }; + /** @description 학생 프로필 정보 */ + 'NativeOAuthResp.StudentInfo': { + /** + * Format: int64 + * @description 학생 ID + */ + id?: number; + /** @description 이메일 */ + email?: string; + /** @description 이름 */ + name?: string; + /** @description 닉네임 */ + nickname?: string; + /** + * Format: date + * @description 생년월일 + */ + birth?: string; + /** + * @description 성별 + * @enum {string} + */ + gender?: 'MALE' | 'FEMALE'; + /** + * @description 학년 + * @enum {string} + */ + grade?: 'ONE' | 'TWO' | 'THREE' | 'N_TIME'; + /** + * @description 선택과목 + * @enum {string} + */ + selectSubject?: 'MIJUKBUN' | 'HWAKTONG' | 'KEEHA'; + /** + * Format: int32 + * @description 수능 등급 + */ + level?: number; + /** + * @description OAuth 제공자 + * @enum {string} + */ + provider?: 'KAKAO' | 'GOOGLE' | 'APPLE'; + /** @description 최초 로그인 여부 (프로필 미완성) */ + isFirstLogin?: boolean; + /** + * Format: int64 + * @description 연결된 선생님 ID + */ + teacherId?: number; + }; NotificationResp: { /** Format: int64 */ id: number; @@ -3736,6 +4521,38 @@ export interface components { /** Format: date-time */ createdAt: string; }; + MockExamResultSubmitRequest: { + /** + * @description GET /api/student/mock-exam/current-type 응답의 type 값을 그대로 전달 + * @example 2026-06 + */ + type: string; + /** + * @description 틀린 문항 번호 목록 + * @example [ + * 1, + * 2, + * 3 + * ] + */ + incorrects: number[]; + /** + * @description 학습 고민 JSON 문자열 + * @example {"text":"문제 풀이 시간이 부족해요"} + */ + question?: string; + }; + MockExamResultResp: { + /** Format: int64 */ + id: number; + type?: string; + incorrects?: number[]; + question?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + }; 'StudentPushDTO.UpdateTokenRequest': { fcmToken: string; }; @@ -3940,16 +4757,10 @@ export interface components { */ occurredAt: string; /** - * @description 이벤트 추가 데이터. 이벤트 타입별 권장 필드는 API 설명을 참고하세요. - * @example { - * "screenName": "Problem", - * "dwellTimeMs": 120000, - * "exitReason": "navigation" - * } + * @description 이벤트 추가 데이터 JSON 문자열. 이벤트 타입별 권장 필드는 API 설명을 참고하세요. + * @example {"screenName":"Problem","dwellTimeMs":120000,"exitReason":"navigation"} */ - metadata?: { - [key: string]: Record; - }; + metadata?: string; /** @description 클라이언트에서 생성한 이벤트 고유 ID (중복 방지용) */ clientEventId?: string; }; @@ -3966,6 +4777,10 @@ export interface components { /** Format: int32 */ count?: number; }; + AdminRoleCreateRequest: { + name: string; + menuIds: number[]; + }; PublishCreateRequest: { /** Format: int64 */ problemSetId: number; @@ -4026,6 +4841,7 @@ export interface components { no: number; questionContent: string; commentContent: string; + bubbles?: components['schemas']['PointingBubbleResp'][]; concepts: components['schemas']['ConceptResp'][]; isQuestionUnderstood?: boolean; isCommentUnderstood?: boolean; @@ -4167,6 +4983,7 @@ export interface components { no?: number; questionContent?: string; commentContent?: string; + bubbles?: components['schemas']['BubbleRequest'][]; concepts?: number[]; }; ProblemCreateRequest: { @@ -4255,6 +5072,22 @@ export interface components { /** @description FCM 지원 여부 */ fcmSupported: boolean; }; + MockExamTypeCreateRequest: { + code: string; + displayName: string; + /** Format: date */ + startDate: string; + /** Format: date */ + endDate: string; + }; + AdminMenuCreateRequest: { + name: string; + /** + * Format: int64 + * @description 상위 메뉴 ID. null이면 최상위 메뉴로 생성 + */ + parentId?: number; + }; /** @description FCM 테스트 발송 요청 */ FcmTestReq: { /** @@ -4292,25 +5125,110 @@ export interface components { studentId?: number; content?: string; }; + UpsertRequest: { + /** + * @description 학생 ID 목록 + * @example [ + * 1, + * 2, + * 3 + * ] + */ + studentIds?: number[]; + /** + * Format: date + * @description 코멘트 기준 일자 + * @example 2026-05-05 + */ + commentDate?: string; + /** + * @description 코멘트 내용 + * @example 오늘도 학습을 잘 진행했습니다. + */ + contentJson?: string; + }; ConceptCreateRequest: { name: string; /** Format: int64 */ categoryId: number; }; + ConceptNodeCreateRequest: { + name: string; + /** Format: int64 */ + nodeTypeId: number; + description?: string; + payload?: { + [key: string]: Record; + }; + }; + NodeTypeCodeCreateRequest: { + code: string; + label: string; + description?: string; + }; + ConceptEdgeCreateRequest: { + /** Format: int64 */ + fromNodeId: number; + /** Format: int64 */ + edgeTypeId: number; + /** Format: int64 */ + toNodeId: number; + }; + EdgeTypeCodeCreateRequest: { + code: string; + label: string; + description?: string; + }; + ConceptActionEdgeCreateRequest: { + /** Format: int64 */ + actionNodeId: number; + /** Format: int64 */ + roleId: number; + /** Format: int64 */ + conceptNodeId: number; + }; + ActionEdgeTypeCodeCreateRequest: { + code: string; + label: string; + description?: string; + }; ConceptCategoryCreateRequest: { name: string; }; + /** @description 접근 가능 메뉴 목록 */ + AdminMenuResp: { + /** Format: int64 */ + id?: number; + name?: string; + /** + * Format: int64 + * @description 상위 메뉴 ID. null이면 최상위 메뉴 + */ + parentId?: number; + }; AdminTokenResp: { /** Format: int64 */ id: number; email: string; + /** @enum {string} */ + adminType: 'SUPER' | 'ROLE_BASED'; token: components['schemas']['JwtResp']; + /** @description 접근 가능 메뉴 목록 */ + accessibleMenus?: components['schemas']['AdminMenuResp'][]; }; AdminLoginReq: { email: string; password: string; }; + AdminRoleAssignRequest: { + /** + * Format: int64 + * @description 역할 ID. null이면 역할 해제 (슈퍼 관리자 전환) + */ + roleId?: number; + }; ListRespPublishResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['PublishResp'][]; @@ -4320,11 +5238,13 @@ export interface components { progress: number; }; ListRespStudentResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['StudentResp'][]; }; PageRespNotListQnAGroupByWeekResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4368,6 +5288,7 @@ export interface components { matchedChatPreview?: string; }; PageRespNotListListChatSearchResultResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4381,11 +5302,13 @@ export interface components { chatResults?: components['schemas']['PageRespNotListListChatSearchResultResp']; }; ListRespNoticeResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['NoticeResp'][]; }; ListRespProblemEntireResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['ProblemEntireResp'][]; @@ -4429,6 +5352,7 @@ export interface components { oneStepMoreContent: string; }; ListRespPointingEntireResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['PointingEntireResp'][]; @@ -4447,12 +5371,14 @@ export interface components { no: number; questionContent: string; commentContent: string; + bubbles?: components['schemas']['PointingBubbleResp'][]; concepts: components['schemas']['ConceptResp'][]; isQuestionUnderstood?: boolean; isCommentUnderstood?: boolean; isScrapped?: boolean; }; ListRespTrashItemResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['TrashItemResp'][]; @@ -4533,26 +5459,31 @@ export interface components { scraps: components['schemas']['ScrapListItemResp'][]; }; ListRespScrapFolderResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['ScrapFolderResp'][]; }; ListRespScrapListItemResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['ScrapListItemResp'][]; }; ListRespSchoolResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['SchoolResp'][]; }; ListRespUploadFileResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['UploadFileResp'][]; }; ListRespQnaFileResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['QnaFileResp'][]; @@ -4568,6 +5499,7 @@ export interface components { isScrapped: boolean; }; ListRespNotificationResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['NotificationResp'][]; @@ -4586,6 +5518,7 @@ export interface components { latestNotification?: components['schemas']['NotificationResp']; }; PageRespNoticeResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4602,6 +5535,7 @@ export interface components { latestNotice?: components['schemas']['NoticeResp']; }; ListRespDiagnosisResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['DiagnosisResp'][]; @@ -4719,6 +5653,7 @@ export interface components { timestamp?: string; }; PageRespTeacherResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4728,6 +5663,7 @@ export interface components { data: components['schemas']['TeacherResp'][]; }; PageRespStudentResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4736,7 +5672,14 @@ export interface components { lastPage: number; data: components['schemas']['StudentResp'][]; }; + AdminRoleResp: { + /** Format: int64 */ + id?: number; + name?: string; + menus?: components['schemas']['AdminMenuResp'][]; + }; PageRespProblemMetaResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4746,6 +5689,7 @@ export interface components { data: components['schemas']['ProblemMetaResp'][]; }; ListRespProblemInfoResp: { + requestId: string; /** Format: int32 */ total: number; data: components['schemas']['ProblemInfoResp'][]; @@ -4754,6 +5698,7 @@ export interface components { customId?: string; }; PageRespProblemSetResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4763,6 +5708,7 @@ export interface components { data: components['schemas']['ProblemSetResp'][]; }; PageRespPracticeTestResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4771,12 +5717,25 @@ export interface components { lastPage: number; data: components['schemas']['PracticeTestResp'][]; }; + ListRespMockExamResultResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['MockExamResultResp'][]; + }; + ListRespMockExamTypeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['MockExamTypeResp'][]; + }; /** @description FCM 상태 응답 */ FcmStatusResp: { /** @description Firebase 초기화 상태 */ initialized?: boolean; }; PageRespConceptResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -4785,7 +5744,44 @@ export interface components { lastPage: number; data: components['schemas']['ConceptResp'][]; }; + ListRespConceptNodeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['ConceptNodeResp'][]; + }; + ListRespNodeTypeCodeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['NodeTypeCodeResp'][]; + }; + ListRespConceptEdgeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['ConceptEdgeResp'][]; + }; + ListRespEdgeTypeCodeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['EdgeTypeCodeResp'][]; + }; + ListRespConceptActionEdgeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['ConceptActionEdgeResp'][]; + }; + ListRespActionEdgeTypeCodeResp: { + requestId: string; + /** Format: int32 */ + total: number; + data: components['schemas']['ActionEdgeTypeCodeResp'][]; + }; PageRespConceptCategoryResp: { + requestId: string; /** Format: int32 */ page: number; /** Format: int32 */ @@ -5023,8 +6019,7 @@ export interface components { path?: string; /** Format: date-time */ timestamp?: string; - rootCause?: string; - stackTrace?: string[]; + requestId?: string; }; }; responses: never; @@ -5199,6 +6194,77 @@ export interface operations { }; }; }; + getHandwriting: { + parameters: { + query?: never; + header?: never; + path: { + publishId: number; + problemId: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['StudyHandwritingResp']; + }; + }; + }; + }; + updateHandwriting: { + parameters: { + query?: never; + header?: never; + path: { + publishId: number; + problemId: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['StudyHandwritingUpdateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['StudyHandwritingResp']; + }; + }; + }; + }; + deleteHandwriting: { + parameters: { + query?: never; + header?: never; + path: { + publishId: number; + problemId: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; updateScrap: { parameters: { query?: never; @@ -5303,7 +6369,7 @@ export interface operations { }; }; }; - getHandwriting: { + getHandwriting_1: { parameters: { query?: never; header?: never; @@ -5325,7 +6391,7 @@ export interface operations { }; }; }; - updateHandwriting: { + updateHandwriting_1: { parameters: { query?: never; header?: never; @@ -5351,7 +6417,7 @@ export interface operations { }; }; }; - deleteHandwriting: { + deleteHandwriting_1: { parameters: { query?: never; header?: never; @@ -5821,6 +6887,50 @@ export interface operations { }; }; }; + update_4: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminRoleUpdateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + delete_2: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; updateStatus_2: { parameters: { query?: never; @@ -5985,7 +7095,7 @@ export interface operations { }; }; }; - update_4: { + update_5: { parameters: { query?: never; header?: never; @@ -6011,7 +7121,7 @@ export interface operations { }; }; }; - delete_2: { + delete_3: { parameters: { query?: never; header?: never; @@ -6053,7 +7163,7 @@ export interface operations { }; }; }; - update_5: { + update_6: { parameters: { query?: never; header?: never; @@ -6064,7 +7174,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['Request']; + 'application/json': components['schemas']['PracticeTestUpdateRequest']; }; }; responses: { @@ -6079,7 +7189,7 @@ export interface operations { }; }; }; - delete_3: { + delete_4: { parameters: { query?: never; header?: never; @@ -6099,7 +7209,33 @@ export interface operations { }; }; }; - update_6: { + update_7: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PointingBubbleUpdateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PointingBubbleResp']; + }; + }; + }; + }; + update_8: { parameters: { query?: never; header?: never; @@ -6125,7 +7261,53 @@ export interface operations { }; }; }; - delete_4: { + delete_5: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateType: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['MockExamTypeUpdateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['MockExamTypeResp']; + }; + }; + }; + }; + deleteType: { parameters: { query?: never; header?: never; @@ -6167,7 +7349,7 @@ export interface operations { }; }; }; - update_7: { + update_9: { parameters: { query?: never; header?: never; @@ -6193,7 +7375,7 @@ export interface operations { }; }; }; - delete_5: { + delete_6: { parameters: { query?: never; header?: never; @@ -6213,18 +7395,18 @@ export interface operations { }; }; }; - update_8: { + update_10: { parameters: { query?: never; header?: never; path: { - conceptId: number; + id: number; }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['ConceptUpdateRequest']; + 'application/json': components['schemas']['UpdateRequest']; }; }; responses: { @@ -6234,52 +7416,43 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ConceptResp']; + '*/*': components['schemas']['DailyCommentResp']; }; }; }; }; - delete_6: { + delete_7: { parameters: { query?: never; header?: never; path: { - conceptId: number; + id: number; }; cookie?: never; }; requestBody?: never; responses: { - /** @description 삭제 성공 */ + /** @description OK */ 200: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description 사용 중인 개념태그는 삭제할 수 없음 */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - '*/*': components['schemas']['ErrorResp']; - }; - }; }; }; - updateCategory: { + update_11: { parameters: { query?: never; header?: never; path: { - categoryId: number; + conceptId: number; }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['ConceptCategoryUpdateRequest']; + 'application/json': components['schemas']['ConceptUpdateRequest']; }; }; responses: { @@ -6289,17 +7462,17 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ConceptCategoryResp']; + '*/*': components['schemas']['ConceptResp']; }; }; }; }; - deleteCategory: { + delete_8: { parameters: { query?: never; header?: never; path: { - categoryId: number; + conceptId: number; }; cookie?: never; }; @@ -6312,7 +7485,7 @@ export interface operations { }; content?: never; }; - /** @description 사용 중인 대분류는 삭제할 수 없음 */ + /** @description 사용 중인 개념태그는 삭제할 수 없음 */ 400: { headers: { [name: string]: unknown; @@ -6323,16 +7496,18 @@ export interface operations { }; }; }; - addChat: { + updateNode: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['ChatCreateRequest']; + 'application/json': components['schemas']['ConceptNodeUpdateRequest']; }; }; responses: { @@ -6342,18 +7517,18 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['QnAResp']; + '*/*': components['schemas']['ConceptNodeResp']; }; }; }; }; - getsAll: { + deleteNode: { parameters: { - query: { - studentId: number; - }; + query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody?: never; @@ -6363,22 +7538,22 @@ export interface operations { headers: { [name: string]: unknown; }; - content: { - '*/*': components['schemas']['ListRespNoticeResp']; - }; + content?: never; }; }; }; - create: { + updateNodeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['NoticeCreateRequest']; + 'application/json': components['schemas']['NodeTypeCodeUpdateRequest']; }; }; responses: { @@ -6388,21 +7563,43 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['NoticeResp']; + '*/*': components['schemas']['NodeTypeCodeResp']; }; }; }; }; - updatePushToken: { + deleteNodeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateEdge: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['TeacherPushDTO.UpdateTokenRequest']; + 'application/json': components['schemas']['ConceptEdgeUpdateRequest']; }; }; responses: { @@ -6412,16 +7609,18 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['TeacherResp']; + '*/*': components['schemas']['ConceptEdgeResp']; }; }; }; }; - toggleAllowPush: { + deleteEdge: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody?: never; @@ -6431,22 +7630,22 @@ export interface operations { headers: { [name: string]: unknown; }; - content: { - '*/*': components['schemas']['TeacherResp']; - }; + content?: never; }; }; }; - refresh: { + updateEdgeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['RefreshReq']; + 'application/json': components['schemas']['EdgeTypeCodeUpdateRequest']; }; }; responses: { @@ -6456,21 +7655,43 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['TeacherTokenResp']; + '*/*': components['schemas']['EdgeTypeCodeResp']; }; }; }; }; - login: { + deleteEdgeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateActionEdge: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['TeacherLoginReq']; + 'application/json': components['schemas']['ConceptActionEdgeUpdateRequest']; }; }; responses: { @@ -6480,23 +7701,21 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['TeacherTokenResp']; + '*/*': components['schemas']['ConceptActionEdgeResp']; }; }; }; }; - feedback: { + deleteActionEdge: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - 'application/json': components['schemas']['PointingFeedbackRequest']; + path: { + id: number; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -6507,16 +7726,18 @@ export interface operations { }; }; }; - submit: { + updateActionEdgeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['SubmissionRequest']; + 'application/json': components['schemas']['ActionEdgeTypeCodeUpdateRequest']; }; }; responses: { @@ -6526,21 +7747,43 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['SubmissionResp']; + '*/*': components['schemas']['ActionEdgeTypeCodeResp']; }; }; }; }; - createScrap: { + deleteActionEdgeType: { parameters: { query?: never; header?: never; - path?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateCategory: { + parameters: { + query?: never; + header?: never; + path: { + categoryId: number; + }; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['ScrapCreateRequest']; + 'application/json': components['schemas']['ConceptCategoryUpdateRequest']; }; }; responses: { @@ -6550,34 +7793,41 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapDetailResp']; + '*/*': components['schemas']['ConceptCategoryResp']; }; }; }; }; - deleteScraps: { + deleteCategory: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - 'application/json': components['schemas']['ScrapBatchDeleteRequest']; + path: { + categoryId: number; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description OK */ + /** @description 삭제 성공 */ 200: { headers: { [name: string]: unknown; }; content?: never; }; + /** @description 사용 중인 대분류는 삭제할 수 없음 */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ErrorResp']; + }; + }; }; }; - toggleScrapFromReadingTip: { + addChat: { parameters: { query?: never; header?: never; @@ -6586,7 +7836,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFromReadingTipCreateRequest']; + 'application/json': components['schemas']['ChatCreateRequest']; }; }; responses: { @@ -6596,23 +7846,21 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapToggleResp']; + '*/*': components['schemas']['QnAResp']; }; }; }; }; - toggleScrapFromProblem: { + getsAll: { parameters: { - query?: never; + query: { + studentId: number; + }; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': components['schemas']['ScrapFromProblemCreateRequest']; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -6620,12 +7868,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapToggleResp']; + '*/*': components['schemas']['ListRespNoticeResp']; }; }; }; }; - toggleScrapFromPointing: { + create: { parameters: { query?: never; header?: never; @@ -6634,7 +7882,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFromPointingCreateRequest']; + 'application/json': components['schemas']['NoticeCreateRequest']; }; }; responses: { @@ -6644,12 +7892,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapToggleResp']; + '*/*': components['schemas']['NoticeResp']; }; }; }; }; - toggleScrapFromOneStepMore: { + updatePushToken: { parameters: { query?: never; header?: never; @@ -6658,7 +7906,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFromOneStepMoreCreateRequest']; + 'application/json': components['schemas']['TeacherPushDTO.UpdateTokenRequest']; }; }; responses: { @@ -6668,23 +7916,19 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapToggleResp']; + '*/*': components['schemas']['TeacherResp']; }; }; }; }; - createScrapFromProblem: { + toggleAllowPush: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': components['schemas']['ScrapFromProblemCreateRequest']; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -6692,12 +7936,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapDetailResp']; + '*/*': components['schemas']['TeacherResp']; }; }; }; }; - unscrapFromProblem: { + refresh: { parameters: { query?: never; header?: never; @@ -6706,7 +7950,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['UnscrapFromProblemRequest']; + 'application/json': components['schemas']['RefreshReq']; }; }; responses: { @@ -6715,11 +7959,13 @@ export interface operations { headers: { [name: string]: unknown; }; - content?: never; + content: { + '*/*': components['schemas']['TeacherTokenResp']; + }; }; }; }; - createScrapFromPointing: { + login: { parameters: { query?: never; header?: never; @@ -6728,7 +7974,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFromPointingCreateRequest']; + 'application/json': components['schemas']['TeacherLoginReq']; }; }; responses: { @@ -6738,12 +7984,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapDetailResp']; + '*/*': components['schemas']['TeacherTokenResp']; }; }; }; }; - unscrapFromPointing: { + feedback: { parameters: { query?: never; header?: never; @@ -6752,7 +7998,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['UnscrapFromPointingRequest']; + 'application/json': components['schemas']['PointingFeedbackRequest']; }; }; responses: { @@ -6765,7 +8011,7 @@ export interface operations { }; }; }; - createScrapFromImage: { + recordBubbleQuestion: { parameters: { query?: never; header?: never; @@ -6774,7 +8020,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFromImageCreateRequest']; + 'application/json': components['schemas']['PointingBubbleQuestionRequest']; }; }; responses: { @@ -6784,19 +8030,23 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapDetailResp']; + '*/*': components['schemas']['PointingBubbleQuestionResponse']; }; }; }; }; - getFolders: { + submit: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + 'application/json': components['schemas']['SubmissionRequest']; + }; + }; responses: { /** @description OK */ 200: { @@ -6804,12 +8054,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ListRespScrapFolderResp']; + '*/*': components['schemas']['SubmissionResp']; }; }; }; }; - createFolder: { + createScrap: { parameters: { query?: never; header?: never; @@ -6818,7 +8068,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ScrapFolderCreateRequest']; + 'application/json': components['schemas']['ScrapCreateRequest']; }; }; responses: { @@ -6828,12 +8078,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ScrapFolderResp']; + '*/*': components['schemas']['ScrapDetailResp']; }; }; }; }; - deleteFolders: { + deleteScraps: { parameters: { query?: never; header?: never; @@ -6842,7 +8092,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': number[]; + 'application/json': components['schemas']['ScrapBatchDeleteRequest']; }; }; responses: { @@ -6855,16 +8105,18 @@ export interface operations { }; }; }; - gets: { + toggleScrapFromReadingTip: { parameters: { - query?: { - query?: string; - }; + query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + 'application/json': components['schemas']['ScrapFromReadingTipCreateRequest']; + }; + }; responses: { /** @description OK */ 200: { @@ -6872,12 +8124,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespNotListQnAGroupByWeekResp']; + '*/*': components['schemas']['ScrapToggleResp']; }; }; }; }; - create_1: { + toggleScrapFromProblem: { parameters: { query?: never; header?: never; @@ -6886,7 +8138,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['QnACreateRequest']; + 'application/json': components['schemas']['ScrapFromProblemCreateRequest']; }; }; responses: { @@ -6896,12 +8148,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['QnAResp']; + '*/*': components['schemas']['ScrapToggleResp']; }; }; }; }; - checkExists: { + toggleScrapFromPointing: { parameters: { query?: never; header?: never; @@ -6910,7 +8162,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['QnACheckRequest']; + 'application/json': components['schemas']['ScrapFromPointingCreateRequest']; }; }; responses: { @@ -6920,12 +8172,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['QnACheckResp']; + '*/*': components['schemas']['ScrapToggleResp']; }; }; }; }; - addChat_1: { + toggleScrapFromOneStepMore: { parameters: { query?: never; header?: never; @@ -6934,7 +8186,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ChatCreateRequest']; + 'application/json': components['schemas']['ScrapFromOneStepMoreCreateRequest']; }; }; responses: { @@ -6944,21 +8196,23 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['QnAResp']; + '*/*': components['schemas']['ScrapToggleResp']; }; }; }; }; - readNotification: { + createScrapFromProblem: { parameters: { query?: never; header?: never; - path: { - notificationId: number; - }; + path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + 'application/json': components['schemas']['ScrapFromProblemCreateRequest']; + }; + }; responses: { /** @description OK */ 200: { @@ -6966,19 +8220,23 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['NotificationResp']; + '*/*': components['schemas']['ScrapDetailResp']; }; }; }; }; - readAllNotifications: { + unscrapFromProblem: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + 'application/json': components['schemas']['UnscrapFromProblemRequest']; + }; + }; responses: { /** @description OK */ 200: { @@ -6989,7 +8247,7 @@ export interface operations { }; }; }; - updatePushToken_1: { + createScrapFromPointing: { parameters: { query?: never; header?: never; @@ -6998,7 +8256,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['StudentPushDTO.UpdateTokenRequest']; + 'application/json': components['schemas']['ScrapFromPointingCreateRequest']; }; }; responses: { @@ -7008,12 +8266,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentResp']; + '*/*': components['schemas']['ScrapDetailResp']; }; }; }; }; - initPushSettings: { + unscrapFromPointing: { parameters: { query?: never; header?: never; @@ -7022,7 +8280,29 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['StudentPushDTO.InitPushRequest']; + 'application/json': components['schemas']['UnscrapFromPointingRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + createScrapFromImage: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ScrapFromImageCreateRequest']; }; }; responses: { @@ -7032,12 +8312,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentPushDTO.SettingsResponse']; + '*/*': components['schemas']['ScrapDetailResp']; }; }; }; }; - toggleAllowPush_1: { + getFolders: { parameters: { query?: never; header?: never; @@ -7052,12 +8332,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentResp']; + '*/*': components['schemas']['ListRespScrapFolderResp']; }; }; }; }; - changePassword: { + createFolder: { parameters: { query?: never; header?: never; @@ -7066,7 +8346,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['StudentPasswordDTO.UpdatePasswordRequest']; + 'application/json': components['schemas']['ScrapFolderCreateRequest']; }; }; responses: { @@ -7076,12 +8356,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentResp']; + '*/*': components['schemas']['ScrapFolderResp']; }; }; }; }; - submitFeedback: { + deleteFolders: { parameters: { query?: never; header?: never; @@ -7090,12 +8370,12 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['FeedbackDTO.Request']; + 'application/json': number[]; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { headers: { [name: string]: unknown; }; @@ -7103,18 +8383,16 @@ export interface operations { }; }; }; - signup: { + gets: { parameters: { - query?: never; + query?: { + query?: string; + }; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': components['schemas']['StudentSignupReq']; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7122,12 +8400,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentTokenResp']; + '*/*': components['schemas']['PageRespNotListQnAGroupByWeekResp']; }; }; }; }; - register: { + create_1: { parameters: { query?: never; header?: never; @@ -7136,7 +8414,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['StudentInitialRegisterDTO.Req']; + 'application/json': components['schemas']['QnACreateRequest']; }; }; responses: { @@ -7146,12 +8424,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentResp']; + '*/*': components['schemas']['QnAResp']; }; }; }; }; - refresh_1: { + checkExists: { parameters: { query?: never; header?: never; @@ -7160,7 +8438,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['RefreshReq']; + 'application/json': components['schemas']['QnACheckRequest']; }; }; responses: { @@ -7170,12 +8448,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentTokenResp']; + '*/*': components['schemas']['QnACheckResp']; }; }; }; }; - quit: { + addChat_1: { parameters: { query?: never; header?: never; @@ -7184,7 +8462,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['WithdrawDTO.Request']; + 'application/json': components['schemas']['ChatCreateRequest']; }; }; responses: { @@ -7193,11 +8471,13 @@ export interface operations { headers: { [name: string]: unknown; }; - content?: never; + content: { + '*/*': components['schemas']['QnAResp']; + }; }; }; }; - resetPassword: { + nativeLogin: { parameters: { query?: never; header?: never; @@ -7206,31 +8486,49 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PasswordResetDTO.ResetPasswordRequest']; + 'application/json': components['schemas']['NativeOAuthReq']; }; }; responses: { - /** @description OK */ + /** @description 로그인 성공 */ 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + '*/*': components['schemas']['NativeOAuthResp']; + }; + }; + /** @description 유효하지 않은 토큰 (OAUTH_001) 또는 유효성 검증 실패 */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['NativeOAuthResp']; + }; + }; + /** @description OAuth 제공자 API 오류 (OAUTH_002) */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['NativeOAuthResp']; + }; }; }; }; - verifyPasswordResetCode: { + readNotification: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - 'application/json': components['schemas']['PasswordResetDTO.VerifyCodeRequest']; + path: { + notificationId: number; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7238,23 +8536,19 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['BooleanResp']; + '*/*': components['schemas']['NotificationResp']; }; }; }; }; - sendPasswordResetCode: { + readAllNotifications: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': components['schemas']['PasswordResetDTO.SendCodeRequest']; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7265,7 +8559,7 @@ export interface operations { }; }; }; - getSocialLoginUrl: { + submit_1: { parameters: { query?: never; header?: never; @@ -7274,7 +8568,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['SocialLoginReq']; + 'application/json': components['schemas']['MockExamResultSubmitRequest']; }; }; responses: { @@ -7284,12 +8578,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['SocialLoginUrlResp']; + '*/*': components['schemas']['MockExamResultResp']; }; }; }; }; - login_1: { + updatePushToken_1: { parameters: { query?: never; header?: never; @@ -7298,7 +8592,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['StudentLoginReq']; + 'application/json': components['schemas']['StudentPushDTO.UpdateTokenRequest']; }; }; responses: { @@ -7308,12 +8602,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['StudentTokenResp']; + '*/*': components['schemas']['StudentResp']; }; }; }; }; - getPreSignedUrl: { + initPushSettings: { parameters: { query?: never; header?: never; @@ -7322,7 +8616,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PreSignedReq']; + 'application/json': components['schemas']['StudentPushDTO.InitPushRequest']; }; }; responses: { @@ -7332,23 +8626,19 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PreSignedResp']; + '*/*': components['schemas']['StudentPushDTO.SettingsResponse']; }; }; }; }; - verify: { + toggleAllowPush_1: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': components['schemas']['PhoneAuthVerifyRequest']; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7356,12 +8646,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['SimpleSuccessResp']; + '*/*': components['schemas']['StudentResp']; }; }; }; }; - send: { + changePassword: { parameters: { query?: never; header?: never; @@ -7370,7 +8660,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PhoneAuthSendRequest']; + 'application/json': components['schemas']['StudentPasswordDTO.UpdatePasswordRequest']; }; }; responses: { @@ -7380,12 +8670,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['SimpleSuccessResp']; + '*/*': components['schemas']['StudentResp']; }; }; }; }; - resend: { + submitFeedback: { parameters: { query?: never; header?: never; @@ -7394,22 +8684,20 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PhoneAuthResendRequest']; + 'application/json': components['schemas']['FeedbackDTO.Request']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; - content: { - '*/*': components['schemas']['SimpleSuccessResp']; - }; + content?: never; }; }; }; - collectEvents: { + signup: { parameters: { query?: never; header?: never; @@ -7418,27 +8706,22 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['UserEventBatchRequest']; + 'application/json': components['schemas']['StudentSignupReq']; }; }; responses: { - /** @description 이벤트 저장 성공 */ - 204: { + /** @description OK */ + 200: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description 잘못된 요청 (검증 실패) */ - 400: { - headers: { - [name: string]: unknown; + content: { + '*/*': components['schemas']['StudentTokenResp']; }; - content?: never; }; }; }; - create_2: { + register: { parameters: { query?: never; header?: never; @@ -7447,7 +8730,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['AdminCreateRequest']; + 'application/json': components['schemas']['StudentInitialRegisterDTO.Req']; }; }; responses: { @@ -7456,22 +8739,24 @@ export interface operations { headers: { [name: string]: unknown; }; - content?: never; + content: { + '*/*': components['schemas']['StudentResp']; + }; }; }; }; - search: { + refresh_1: { parameters: { - query?: { - query?: string; - page?: number; - size?: number; - }; + query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + 'application/json': components['schemas']['RefreshReq']; + }; + }; responses: { /** @description OK */ 200: { @@ -7479,12 +8764,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespTeacherResp']; + '*/*': components['schemas']['StudentTokenResp']; }; }; }; }; - create_3: { + quit: { parameters: { query?: never; header?: never; @@ -7493,7 +8778,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['TeacherCreateRequest']; + 'application/json': components['schemas']['WithdrawDTO.Request']; }; }; responses: { @@ -7502,25 +8787,20 @@ export interface operations { headers: { [name: string]: unknown; }; - content: { - '*/*': components['schemas']['TeacherResp']; - }; + content?: never; }; }; }; - batch: { + resetPassword: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: { + requestBody: { content: { - 'multipart/form-data': { - /** Format: binary */ - file: string; - }; + 'application/json': components['schemas']['PasswordResetDTO.ResetPasswordRequest']; }; }; responses: { @@ -7529,13 +8809,11 @@ export interface operations { headers: { [name: string]: unknown; }; - content: { - '*/*': components['schemas']['SchoolSaveRespDTO']; - }; + content?: never; }; }; }; - addChat_2: { + verifyPasswordResetCode: { parameters: { query?: never; header?: never; @@ -7544,7 +8822,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ChatCreateRequest']; + 'application/json': components['schemas']['PasswordResetDTO.VerifyCodeRequest']; }; }; responses: { @@ -7554,7 +8832,365 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['QnAResp']; + '*/*': components['schemas']['BooleanResp']; + }; + }; + }; + }; + sendPasswordResetCode: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PasswordResetDTO.SendCodeRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSocialLoginUrl: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SocialLoginReq']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['SocialLoginUrlResp']; + }; + }; + }; + }; + login_1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['StudentLoginReq']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['StudentTokenResp']; + }; + }; + }; + }; + getPreSignedUrl: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PreSignedReq']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PreSignedResp']; + }; + }; + }; + }; + verify: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PhoneAuthVerifyRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['SimpleSuccessResp']; + }; + }; + }; + }; + send: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PhoneAuthSendRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['SimpleSuccessResp']; + }; + }; + }; + }; + resend: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PhoneAuthResendRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['SimpleSuccessResp']; + }; + }; + }; + }; + collectEvents: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UserEventBatchRequest']; + }; + }; + responses: { + /** @description 이벤트 저장 성공 */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description 잘못된 요청 (검증 실패) */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + create_2: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + search: { + parameters: { + query?: { + query?: string; + page?: number; + size?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PageRespTeacherResp']; + }; + }; + }; + }; + create_3: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['TeacherCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['TeacherResp']; + }; + }; + }; + }; + batch: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'multipart/form-data': { + /** Format: binary */ + file: string; + }; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['SchoolSaveRespDTO']; + }; + }; + }; + }; + findAll: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['AdminRoleResp'][]; + }; + }; + }; + }; + create_4: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminRoleCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + addChat_2: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ChatCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['QnAResp']; }; }; }; @@ -7562,9 +9198,203 @@ export interface operations { search_1: { parameters: { query?: { - year?: number; - month?: number; - studentId?: number; + year?: number; + month?: number; + studentId?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ListRespPublishResp']; + }; + }; + }; + }; + create_5: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PublishCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PublishResp']; + }; + }; + }; + }; + search_2: { + parameters: { + query?: { + customId?: string; + title?: string; + concepts?: number[]; + problemType?: 'MAIN_PROBLEM' | 'CHILD_PROBLEM'; + page?: number; + size?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PageRespProblemMetaResp']; + }; + }; + }; + }; + createProblem: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ProblemCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ProblemInfoResp']; + }; + }; + }; + }; + getChildren: { + parameters: { + query?: never; + header?: never; + path: { + parentId: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ListRespProblemInfoResp']; + }; + }; + }; + }; + addChild: { + parameters: { + query?: never; + header?: never; + path: { + parentId: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ProblemCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ProblemInfoResp']; + }; + }; + }; + }; + removeChildren: { + parameters: { + query: { + childIds: number[]; + }; + header?: never; + path: { + parentId: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + createProblemWithChild: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ProblemEntireCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ProblemInfoResp']; + }; + }; + }; + }; + search_3: { + parameters: { + query?: { + setTitle?: string; + problemTitle?: string; + page?: number; + size?: number; }; header?: never; path?: never; @@ -7578,12 +9408,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ListRespPublishResp']; + '*/*': components['schemas']['PageRespProblemSetResp']; }; }; }; }; - create_4: { + create_6: { parameters: { query?: never; header?: never; @@ -7592,7 +9422,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PublishCreateRequest']; + 'application/json': components['schemas']['ProblemSetCreateRequest']; }; }; responses: { @@ -7602,18 +9432,18 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PublishResp']; + '*/*': components['schemas']['ProblemSetResp']; }; }; }; }; - search_2: { + search_4: { parameters: { query?: { - customId?: string; - title?: string; - concepts?: number[]; - problemType?: 'MAIN_PROBLEM' | 'CHILD_PROBLEM'; + query?: string; + year?: number; + month?: number; + grade?: number; page?: number; size?: number; }; @@ -7629,12 +9459,216 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespProblemMetaResp']; + '*/*': components['schemas']['PageRespPracticeTestResp']; }; }; }; }; - createProblem: { + create_7: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PracticeTestCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['PracticeTestResp']; + }; + }; + }; + }; + redirect: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': string; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': string; + }; + }; + }; + }; + sendNotification: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['NotificationSendRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['NotificationSendResp']; + }; + }; + }; + }; + getsAll_1: { + parameters: { + query: { + studentId: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ListRespNoticeResp']; + }; + }; + }; + }; + create_8: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['NoticeCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['NoticeResp']; + }; + }; + }; + }; + getAllTypes: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ListRespMockExamTypeResp']; + }; + }; + }; + }; + createType: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['MockExamTypeCreateRequest']; + }; + }; + responses: { + /** @description Created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['MockExamTypeResp']; + }; + }; + }; + }; + findAll_1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['AdminMenuResp'][]; + }; + }; + }; + }; + create_9: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminMenuCreateRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + sendTestPush: { parameters: { query?: never; header?: never; @@ -7643,7 +9677,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ProblemCreateRequest']; + 'application/json': components['schemas']['FcmTestReq']; }; }; responses: { @@ -7653,18 +9687,18 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ProblemInfoResp']; + '*/*': components['schemas']['FcmTestResp']; }; }; }; }; - getChildren: { + gets_1: { parameters: { - query?: never; - header?: never; - path: { - parentId: number; + query: { + studentId: number; }; + header?: never; + path?: never; cookie?: never; }; requestBody?: never; @@ -7675,23 +9709,21 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ListRespProblemInfoResp']; + '*/*': components['schemas']['ListRespDiagnosisResp']; }; }; }; }; - addChild: { + create_10: { parameters: { query?: never; header?: never; - path: { - parentId: number; - }; + path?: never; cookie?: never; }; requestBody: { content: { - 'application/json': components['schemas']['ProblemCreateRequest']; + 'application/json': components['schemas']['DiagnosisCreateReq']; }; }; responses: { @@ -7701,20 +9733,27 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ProblemInfoResp']; + '*/*': components['schemas']['DiagnosisResp']; }; }; }; }; - removeChildren: { + getByStudentAndDate: { parameters: { - query: { - childIds: number[]; + query?: { + /** + * @description 학생 ID + * @example 1 + */ + studentId?: number; + /** + * @description 조회 기준 일자 + * @example 2026-05-05 + */ + commentDate?: string; }; header?: never; - path: { - parentId: number; - }; + path?: never; cookie?: never; }; requestBody?: never; @@ -7724,11 +9763,13 @@ export interface operations { headers: { [name: string]: unknown; }; - content?: never; + content: { + '*/*': components['schemas']['DailyCommentResp'][]; + }; }; }; }; - createProblemWithChild: { + upsert: { parameters: { query?: never; header?: never; @@ -7737,7 +9778,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ProblemEntireCreateRequest']; + 'application/json': components['schemas']['UpsertRequest']; }; }; responses: { @@ -7747,16 +9788,16 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ProblemInfoResp']; + '*/*': components['schemas']['DailyCommentResp'][]; }; }; }; }; - search_3: { + search_5: { parameters: { query?: { - setTitle?: string; - problemTitle?: string; + query?: string; + categoryId?: number; page?: number; size?: number; }; @@ -7772,12 +9813,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespProblemSetResp']; + '*/*': components['schemas']['PageRespConceptResp']; }; }; }; }; - create_5: { + create_11: { parameters: { query?: never; header?: never; @@ -7786,7 +9827,7 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ProblemSetCreateRequest']; + 'application/json': components['schemas']['ConceptCreateRequest']; }; }; responses: { @@ -7796,21 +9837,14 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ProblemSetResp']; + '*/*': components['schemas']['ConceptResp']; }; }; }; }; - search_4: { + getNodes: { parameters: { - query?: { - query?: string; - year?: number; - month?: number; - grade?: number; - page?: number; - size?: number; - }; + query?: never; header?: never; path?: never; cookie?: never; @@ -7823,12 +9857,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespPracticeTestResp']; + '*/*': components['schemas']['ListRespConceptNodeResp']; }; }; }; }; - create_6: { + createNode: { parameters: { query?: never; header?: never; @@ -7837,33 +9871,29 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['PracticeTestCreateRequest']; + 'application/json': components['schemas']['ConceptNodeCreateRequest']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PracticeTestResp']; + '*/*': components['schemas']['ConceptNodeResp']; }; }; }; }; - redirect: { + getNodeTypes: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - 'application/json': string; - }; - }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7871,12 +9901,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': string; + '*/*': components['schemas']['ListRespNodeTypeCodeResp']; }; }; }; }; - sendNotification: { + createNodeType: { parameters: { query?: never; header?: never; @@ -7885,26 +9915,24 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['NotificationSendRequest']; + 'application/json': components['schemas']['NodeTypeCodeCreateRequest']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; content: { - '*/*': components['schemas']['NotificationSendResp']; + '*/*': components['schemas']['NodeTypeCodeResp']; }; }; }; }; - getsAll_1: { + getEdges: { parameters: { - query: { - studentId: number; - }; + query?: never; header?: never; path?: never; cookie?: never; @@ -7917,12 +9945,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ListRespNoticeResp']; + '*/*': components['schemas']['ListRespConceptEdgeResp']; }; }; }; }; - create_7: { + createEdge: { parameters: { query?: never; header?: never; @@ -7931,9 +9959,29 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['NoticeCreateRequest']; + 'application/json': components['schemas']['ConceptEdgeCreateRequest']; + }; + }; + responses: { + /** @description Created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ConceptEdgeResp']; + }; }; }; + }; + getEdgeTypes: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; responses: { /** @description OK */ 200: { @@ -7941,12 +9989,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['NoticeResp']; + '*/*': components['schemas']['ListRespEdgeTypeCodeResp']; }; }; }; }; - sendTestPush: { + createEdgeType: { parameters: { query?: never; header?: never; @@ -7955,26 +10003,24 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['FcmTestReq']; + 'application/json': components['schemas']['EdgeTypeCodeCreateRequest']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; content: { - '*/*': components['schemas']['FcmTestResp']; + '*/*': components['schemas']['EdgeTypeCodeResp']; }; }; }; }; - gets_1: { + getActionEdges: { parameters: { - query: { - studentId: number; - }; + query?: never; header?: never; path?: never; cookie?: never; @@ -7987,12 +10033,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ListRespDiagnosisResp']; + '*/*': components['schemas']['ListRespConceptActionEdgeResp']; }; }; }; }; - create_8: { + createActionEdge: { parameters: { query?: never; header?: never; @@ -8001,29 +10047,24 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['DiagnosisCreateReq']; + 'application/json': components['schemas']['ConceptActionEdgeCreateRequest']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; content: { - '*/*': components['schemas']['DiagnosisResp']; + '*/*': components['schemas']['ConceptActionEdgeResp']; }; }; }; }; - search_5: { + getActionEdgeTypes: { parameters: { - query?: { - query?: string; - categoryId?: number; - page?: number; - size?: number; - }; + query?: never; header?: never; path?: never; cookie?: never; @@ -8036,12 +10077,12 @@ export interface operations { [name: string]: unknown; }; content: { - '*/*': components['schemas']['PageRespConceptResp']; + '*/*': components['schemas']['ListRespActionEdgeTypeCodeResp']; }; }; }; }; - create_9: { + createActionEdgeType: { parameters: { query?: never; header?: never; @@ -8050,17 +10091,17 @@ export interface operations { }; requestBody: { content: { - 'application/json': components['schemas']['ConceptCreateRequest']; + 'application/json': components['schemas']['ActionEdgeTypeCodeCreateRequest']; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { headers: { [name: string]: unknown; }; content: { - '*/*': components['schemas']['ConceptResp']; + '*/*': components['schemas']['ActionEdgeTypeCodeResp']; }; }; }; @@ -8161,6 +10202,30 @@ export interface operations { }; }; }; + assignRole: { + parameters: { + query?: never; + header?: never; + path: { + id: number; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminRoleAssignRequest']; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; oauthRedirectExample: { parameters: { query: { @@ -9030,6 +11095,26 @@ export interface operations { }; }; }; + getCurrentType: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['MockExamTypeResp']; + }; + }; + }; + }; gets_3: { parameters: { query?: never; @@ -9092,6 +11177,32 @@ export interface operations { }; }; }; + getByDate: { + parameters: { + query?: { + /** + * @description 조회 기준 일자 + * @example 2026-05-05 + */ + commentDate?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['DailyCommentResp'][]; + }; + }; + }; + }; existsByEmail: { parameters: { query: { @@ -9175,26 +11286,6 @@ export interface operations { }; }; }; - throwException: { - parameters: { - query?: { - message?: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; refresh_3: { parameters: { query?: never; @@ -9305,7 +11396,7 @@ export interface operations { }; }; }; - delete_7: { + delete_9: { parameters: { query?: never; header?: never; @@ -9390,6 +11481,28 @@ export interface operations { }; }; }; + getByStudent: { + parameters: { + query: { + studentId: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + '*/*': components['schemas']['ListRespMockExamResultResp']; + }; + }; + }; + }; getStatus: { parameters: { query?: never; @@ -9620,7 +11733,7 @@ export interface operations { }; }; }; - delete_8: { + delete_10: { parameters: { query?: never; header?: never; @@ -9640,7 +11753,7 @@ export interface operations { }; }; }; - delete_9: { + delete_11: { parameters: { query?: never; header?: never; From 3bbc32e0bb8508c5103eacf0845237b4da5e7963 Mon Sep 17 00:00:00 2001 From: b0nsu <125778250+b0nsu@users.noreply.github.com> Date: Tue, 5 May 2026 21:26:10 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(scrap):=20MAT-542=20handwriting=20data?= =?UTF-8?q?Json=20=EC=A0=84=ED=99=98=20=E2=80=94=20base64=20wrapping=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 5초 autosave 메인 스레드 4단계 직렬화(stringify → encodeURIComponent → unescape → btoa)를 1단계(JSON.stringify)로 축소. handwritingEncoder - canonicalize: Stroke / Point / TextItem 의 키 순서를 명시 재구성하여 byte-stable JSON 출력 보장 (동일 입력 → 동일 출력). - decodeHandwritingData: 응답 객체만 받는 단일 시그니처. dataJson 우선, 없으면 data(base64) fallback, 둘 다 없으면 빈값. 옛 strokes-only 배열 형식 호환 유지. useHandwritingManager - PUT body 를 { dataJson } 으로 (data 미포함) — 자연 마이그레이션. - 응답 분기를 decodeHandwritingData(handwritingData) 로 단순화. Stacked on PR #312 — base: fix/mat-524-autosave-data-loss. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../scrap/hooks/useHandwritingManager.ts | 12 +-- .../student/scrap/utils/handwritingEncoder.ts | 93 +++++++++---------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/apps/native/src/features/student/scrap/hooks/useHandwritingManager.ts b/apps/native/src/features/student/scrap/hooks/useHandwritingManager.ts index ebd1b53ee..8b73c05e5 100644 --- a/apps/native/src/features/student/scrap/hooks/useHandwritingManager.ts +++ b/apps/native/src/features/student/scrap/hooks/useHandwritingManager.ts @@ -118,8 +118,8 @@ export function useHandwritingManager({ scrapId }: UseHandwritingManagerProps) { if (appliedScrapIdRef.current === scrapId) return; if (!canvasMounted) return; try { - const decoded = handwritingData?.data - ? decodeHandwritingData(handwritingData.data) + const decoded = handwritingData + ? decodeHandwritingData(handwritingData) : { strokes: [] as Stroke[], texts: [] as TextItem[] }; applyData(decoded.strokes, decoded.texts); } catch (e) { @@ -152,10 +152,10 @@ export function useHandwritingManager({ scrapId }: UseHandwritingManagerProps) { hasCanvas: !!c, }); if (decision !== 'allow' || !c) return; - const data = encodeHandwritingData(c.getStrokes() ?? [], c.getTexts() ?? []); + const dataJson = encodeHandwritingData(c.getStrokes() ?? [], c.getTexts() ?? []); needsSaveRef.current = false; updateMutationRef.current.mutate( - { scrapId, request: { data } }, + { scrapId, request: { dataJson } }, { // autosave 는 silent — 토스트 없이 다음 interval 에 재시도 onError: () => { @@ -177,12 +177,12 @@ export function useHandwritingManager({ scrapId }: UseHandwritingManagerProps) { }); if (decision !== 'allow' || !c) return; - const data = encodeHandwritingData(c.getStrokes() ?? [], c.getTexts() ?? []); + const dataJson = encodeHandwritingData(c.getStrokes() ?? [], c.getTexts() ?? []); needsSaveRef.current = false; try { await Promise.race([ - updateMutationRef.current.mutateAsync({ scrapId, request: { data } }), + updateMutationRef.current.mutateAsync({ scrapId, request: { dataJson } }), new Promise((_, reject) => setTimeout(() => reject(new Error('flush-timeout')), FLUSH_TIMEOUT_MS) ), diff --git a/apps/native/src/features/student/scrap/utils/handwritingEncoder.ts b/apps/native/src/features/student/scrap/utils/handwritingEncoder.ts index d7cf79d38..743e845ff 100644 --- a/apps/native/src/features/student/scrap/utils/handwritingEncoder.ts +++ b/apps/native/src/features/student/scrap/utils/handwritingEncoder.ts @@ -5,59 +5,56 @@ export interface HandwritingData { texts: TextItem[]; } -/** - * 필기 데이터를 Base64로 인코딩합니다. - * @param strokes - 그리기 스트로크 배열 - * @param texts - 텍스트 아이템 배열 - * @returns Base64로 인코딩된 문자열 - */ -export function encodeHandwritingData(strokes: Stroke[], texts: TextItem[]): string { - const data: HandwritingData = { - strokes: strokes || [], - texts: texts || [], +type DecodeSource = { + dataJson?: string | null; + data?: string | null; +}; + +// 캐노니컬 키 순서로 재구성한다 — 동일 입력에 대한 byte-stable JSON 출력 보장. +function canonicalize(strokes: Stroke[], texts: TextItem[]): HandwritingData { + return { + strokes: strokes.map((s) => ({ + points: s.points.map((p) => ({ x: p.x, y: p.y })), + color: s.color, + width: s.width, + })), + texts: texts.map((t) => ({ + id: t.id, + text: t.text, + x: t.x, + y: t.y, + fontSize: t.fontSize, + color: t.color, + })), }; - const jsonString = JSON.stringify(data); - const base64Data = btoa(unescape(encodeURIComponent(jsonString))); - return base64Data; } -/** - * Base64로 인코딩된 필기 데이터를 디코딩합니다. - * @param base64Data - Base64로 인코딩된 문자열 - * @returns 디코딩된 필기 데이터 (strokes, texts) - * @throws 디코딩 실패 시 에러 - */ -export function decodeHandwritingData(base64Data: string): HandwritingData { - try { - const decodedData = decodeURIComponent(escape(atob(base64Data))); - const data = JSON.parse(decodedData); +export function encodeHandwritingData(strokes: Stroke[], texts: TextItem[]): string { + return JSON.stringify(canonicalize(strokes ?? [], texts ?? [])); +} - // 이전 형식 호환성: strokes만 있는 경우와 { strokes, texts } 형식 모두 지원 - if (Array.isArray(data)) { - // 이전 형식: strokes 배열만 - return { - strokes: data, - texts: [], - }; - } else { - // 새 형식: { strokes, texts } 객체 - return { - strokes: data.strokes || [], - texts: data.texts || [], - }; - } - } catch (error) { - console.error('필기 데이터 디코딩 실패:', error); - throw error; +function parseHandwriting(jsonString: string): HandwritingData { + const parsed = JSON.parse(jsonString); + if (Array.isArray(parsed)) { + return { strokes: parsed, texts: [] }; + } + return { + strokes: parsed.strokes ?? [], + texts: parsed.texts ?? [], + }; +} + +export function decodeHandwritingData(source: DecodeSource): HandwritingData { + if (source.dataJson && source.dataJson.length > 0) { + return parseHandwriting(source.dataJson); + } + if (source.data && source.data.length > 0) { + const decoded = decodeURIComponent(escape(atob(source.data))); + return parseHandwriting(decoded); } + return { strokes: [], texts: [] }; } -/** - * 두 필기 데이터가 동일한지 비교합니다. - * @param data1 - 첫 번째 Base64 인코딩된 데이터 - * @param data2 - 두 번째 Base64 인코딩된 데이터 - * @returns 동일 여부 - */ -export function isSameHandwritingData(data1: string, data2: string): boolean { - return data1 === data2; +export function isSameHandwritingData(a: string, b: string): boolean { + return a === b; }