{"openapi":"3.1.0","info":{"title":"약나루 API","description":"약나루(약 배송) 통합 백엔드 API. 앱(React Native 회원용)과 관리자웹(약사·운영자용)이 같은 서버를 사용한다.\n\n### 기본 규약\n- 모든 경로는 `/api/v1` 로 시작한다(헬스 체크 `/` 제외).\n- **읽기는 GET, 나머지(생성·수정·삭제·상태 변경)는 전부 POST.** PATCH / PUT / DELETE 는 쓰지 않으며 호출하면 `405 COMMON_005`.\n- 삭제는 `POST .../delete`, 수정은 `POST .../update`, 상태 변경은 `POST .../update-status` 처럼 동사 접미사로 구분한다.\n- **식별자 위치**: 단건 조회는 쿼리 파라미터(`/detail?id=`, `/detail?code=`), 수정·삭제는 요청 본문의 식별자 필드(`prescriptionId`, `addressId`, `pharmacyCode`, `postId` 등). 경로 변수는 게시판 카테고리의 `{board}`(faq | qna) 뿐이다.\n- 페이징: `page`(0부터) + `perPage`. 목록 응답은 Spring Data `Page` 형태(`content`, `totalElements`, `totalPages`, `number`, `size`, `last` ...)이며 일부 앱 목록은 배열이다.\n- 날짜/시각은 ISO-8601 문자열(`2026-09-11`, `2026-09-11T10:15:30.123`), 금액은 숫자(원).\n\n### 응답 형태\n성공: `{\"success\": true, \"data\": ...}` — `data` 가 없는 작업은 `{\"success\": true}` 만 온다.\n실패: `{\"success\": false, \"error\": {\"code\": \"...\", \"message\": \"...\"}}` — HTTP 상태코드와 함께 온다. null 필드는 응답에서 생략된다.\n\n| code | HTTP | 의미 |\n|---|---|---|\n| COMMON_001 | 400 | 잘못된 요청(필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩) |\n| COMMON_002 | 500 | 서버 내부 오류 |\n| COMMON_003 | 404 | 리소스 없음 / 존재하지 않는 경로 |\n| COMMON_004 | 500 | 메일 발송 실패(임시 비밀번호) |\n| COMMON_005 | 405 | 지원하지 않는 메서드(PATCH/PUT/DELETE) |\n| AUTH_001 | 401 | 인증 필요(토큰 없음) |\n| AUTH_002 | 401 | 아이디 또는 비밀번호 불일치 |\n| AUTH_003 | 401 | 토큰 만료 |\n| AUTH_004 | 401 | 유효하지 않은 토큰 |\n| AUTH_005 | 403 | 권한 없음(역할 부족, 다른 종류 토큰, 타인 자원, 정지·검토대기 계정) |\n| MEMBER_001 | 404 | 회원 없음 |\n| MEMBER_002 | 409 | 이미 가입된 이메일 |\n| MEMBER_003 | 409 | 이미 가입된 본인인증(DI) |\n| MEMBER_004 | 403 | 탈퇴한 회원/계정 |\n| MEMBER_005 | 400 | 추천인 코드 무효 |\n\n### 인증 — 두 종류의 토큰\n둘 다 `Authorization: Bearer {accessToken}` 헤더로 보내며(우측 Authorize 버튼), access 토큰 30분 / refresh 토큰 14일이다.\n1. **앱 회원 토큰** — `POST /api/v1/auth/login` (userType=USER, role USER). 앱의 회원 API 에만 쓴다.\n2. **관리자 토큰** — `POST /api/v1/admin/auth/login` (userType=ADMIN, role SYSTEM_ADMIN 운영자 / PHARMACY_ADMIN 약사). 관리자 API(`/api/v1/admin/**`)와 일부 관리자 전용 오퍼레이션에 쓴다.\n\n서로 다른 종류의 토큰으로 호출하면 `403 AUTH_005`. 약사(PHARMACY_ADMIN)는 처방전·주문·매출·대시보드에서 자기에게 매핑된 약국 데이터만 본다.\n각 오퍼레이션 설명 끝에 필요한 토큰(회원 토큰 / 관리자 토큰 / SYSTEM_ADMIN 토큰 / 로그인 불필요)을 적어 두었다.\n\n### 문서 그룹\n우측 상단 셀렉트에서 **앱 API**(회원용 + 공개) 와 **관리자 API**(관리자웹용 + 약사 회원가입 + 관리자 전용 오퍼레이션)를 골라 볼 수 있다.\n","version":"v1"},"servers":[{"url":"http://118.131.251.206:39080","description":"Generated server url"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"관리자 / 게시판","description":"관리자웹 게시판 관리 메뉴(공지 관리 / FAQ 관리 / QnA 답변 / 카테고리). 앱에 보이는 공지·FAQ 작성과 회원 문의 답변, FAQ·QnA 카테고리 운영. SYSTEM_ADMIN 토큰 전용이며 쓰기 작업은 모두 감사기록을 남긴다. 목록 조회(공지·FAQ)는 앱과 같은 공개 API(/api/v1/bbs/notices, /faqs)를 쓴다."},{"name":"처방전·주문(앱)","description":"앱의 처방전 접수(촬영 → 인식 → 약국 선택 → 등록)와, 등록된 처방전을 주문 관점으로 보는 주문 내역·상세. 상태코드: 01 발송(접수) → 02 조제가능(결제 대기) → 04 결제완료 → 05 조제완료(방문수령) 또는 06 배송중 → 07 배송완료 → 010 수령완료, 03 조제불가, 08 미방문, 09 오류. 모두 회원 토큰 필요."},{"name":"관리자 / 자격 심사","description":"관리자웹 약 배송 자격 메뉴. 회원이 올린 자격 신청(서류)을 검색·열람하고 승인/반려한다. 관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 필요. 자격 신청은 약국에 속하지 않으므로 약사도 전체 신청을 본다."},{"name":"관리자 / 메뉴·권한관리","description":"관리자웹 [시스템 관리 > 메뉴관리 · 권한관리] 메뉴. 사이드바 구성(이름·순서·노출)과 권한별로 보여줄 메뉴를 코드 수정 없이 바꾼다. 메뉴코드는 관리자웹 화면 라우트와 1:1 이라, 화면이 없는 코드를 만들면 메뉴는 보이지만 눌러도 빈 화면이 된다. 메뉴를 열어줘도 서버의 API 권한 검사는 그대로라 권한 없는 기능은 막힌다."},{"name":"개발용(dev)","description":"dev/local 프로파일에서만 뜨는 테스트 데이터 초기화 API. 인증 없이 호출되며 운영(prod)에는 존재하지 않는다. 회원·약국·관리자 같은 마스터 데이터는 건드리지 않는다."},{"name":"관리자 / 인증","description":"관리자웹(약사 PHARMACY_ADMIN, 운영자 SYSTEM_ADMIN) 로그인·토큰 갱신·비밀번호 찾기. 여기서 발급한 토큰은 관리자용(userType=ADMIN)이며 앱 회원 API 와 섞어 쓸 수 없다. 모두 로그인 없이 호출한다."},{"name":"관리자 / 약품 마스터","description":"관리자웹 시스템 관리 > 약품 마스터 메뉴. 심평원 약제급여목록표(약가파일) 엑셀을 적재하고 EDI 약품코드로 약품명·업체·상한가를 조회한다. 적재는 SYSTEM_ADMIN 전용, 조회는 약사(PHARMACY_ADMIN)도 처방전 상세에서 쓴다."},{"name":"앱 설정","description":"앱 부팅 시 읽는 플랫폼별 운영 플래그. 강제 업데이트(up_*), 약관 재동의(agree_*), 팝업(popup_*), 서버 점검(server_*) 4종 차단 모달의 트리거. 조회는 공개, 갱신은 SYSTEM_ADMIN 토큰 전용."},{"name":"공통코드","description":"앱이 상태 이름·안내 문구를 서버에서 받아 쓰기 위한 읽기 전용 코드 조회. 관리자웹 [시스템 관리 > 코드관리] 에서 이름을 바꾸면 앱도 다음 조회부터 바뀐 이름을 쓴다. 사용중인 코드만 내려가며, 회원 토큰으로 호출한다."},{"name":"관리자 / 약국","description":"관리자웹 약국 관리 메뉴. 약국 등록·정보 수정·수수료·검토 메모와 약사 회원가입 검토(승인/반려), 매핑 약사·첨부 서류 조회. 약국 목록 자체는 앱과 같은 공개 API(GET /api/v1/pharmacies)를 쓴다. SYSTEM_ADMIN 토큰 전용이며 쓰기 작업은 모두 감사기록을 남긴다."},{"name":"관리자 / 회원","description":"관리자웹 회원 관리(앱) 메뉴. 앱 회원 검색·상세·상태 변경. SYSTEM_ADMIN 토큰 전용."},{"name":"푸시(앱)","description":"FCM 토큰 구독/해제와 앱 알림함(인박스). 서버가 발송한 모든 푸시는 메시지 이력으로 남아 알림함에서 다시 볼 수 있다. 발송(send)은 SYSTEM_ADMIN 전용이며, 처방전 상태 변경·자격 심사·공지·문의 답변 푸시는 각 서비스가 자동으로 발송한다."},{"name":"배송지(앱)","description":"앱 회원의 택배 수령 배송지 관리. 목록·추가·수정·삭제 모두 회원 토큰이 필요하며, 기본 배송지는 서버가 자동으로 관리한다."},{"name":"게시판(앱)","description":"앱 공지사항·FAQ(공개)와 1:1 문의 Q&A(회원 토큰 필요). 공지·FAQ 는 관리자웹 게시판 관리에서 작성한 글을 읽기만 한다."},{"name":"관리자 / 내 정보","description":"로그인한 관리자 본인의 프로필·비밀번호와, 약사(PHARMACY_ADMIN)가 자기 약국 정보를 직접 관리하는 약국정보 메뉴용 API. 관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 필요. 아이디·역할·상태·약국 매핑은 여기서 바꿀 수 없고 운영자가 관리자 계정 메뉴에서 처리한다."},{"name":"관리자 / 대체약품","description":"원외처방 대체약품 자료(원처방 약품 ↔ 같은 주성분 대체 약품 매핑) 조회 전용. 관리자웹 처방전 상세의 대체약 조회 팝업이 사용한다. 관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 필요. 자료 적재 API 는 없고 DB 에 직접 넣는다."},{"name":"약사 회원가입","description":"관리자웹 회원가입 화면에서 약사가 직접 가입 신청하는 공개 API. 신청 즉시 약사 계정(PENDING)과 약국이 만들어지고, 운영자가 약국 관리에서 승인해야 로그인할 수 있다."},{"name":"자격 심사(앱)","description":"약 배송(택배 수령) 자격 신청. 회원이 4종 카테고리 중 하나를 골라 증빙 서류를 올리면 심사중(I)으로 접수되고 관리자가 승인(S)/반려(R)한다. 승인/반려 오퍼레이션은 관리자 토큰 전용이며 관리자 API 의 /admin/eligibility/approve, /reject 와 같은 동작이다."},{"name":"회원(앱)","description":"앱 회원가입·중복확인·비밀번호 재설정(로그인 불필요)과 내 정보 조회/수정, 비밀번호 변경, 광고 수신동의, 탈퇴(회원 토큰 필요)."},{"name":"헬스 체크","description":"서버 기동 확인용. 배포 스크립트나 로드밸런서가 호출하며 인증이 필요 없다."},{"name":"인증(앱)","description":"앱 회원 로그인·토큰 갱신·로그아웃. 여기서 발급한 토큰은 회원용(userType=USER)이며 관리자 API(/api/v1/admin/**)에는 쓸 수 없다. 모두 로그인 없이 호출한다."},{"name":"관리자 / 관리자 계정","description":"관리자웹 시스템 관리 > 관리자 계정 메뉴. 약사·운영자 계정의 검색·생성·수정·비밀번호 초기화와 약사-약국 매핑. SYSTEM_ADMIN 토큰 전용이며 쓰기 작업은 모두 감사기록을 남긴다."},{"name":"관리자 / 주문·매출","description":"관리자웹 주문 관리·매출 정산 메뉴. 처방전을 주문/회계 관점으로 조회하고 약국별 매출을 집계하며 Excel 로 내려받는다. 관리자 토큰 필요: SYSTEM_ADMIN 은 전체, PHARMACY_ADMIN 은 매핑된 소속 약국만."},{"name":"관리자 / 처방전","description":"관리자웹 처방전 관리 메뉴. 약사가 접수된 처방전을 확인하고 상태(조제가능/불가, 조제완료, 배송중 등)·가격·복약안내·송장을 갱신한다. 관리자 토큰 필요: SYSTEM_ADMIN 은 전체, PHARMACY_ADMIN 은 매핑된 소속 약국 처방전만 보이고 수정할 수 있다(약국 밖 건은 AUTH_005)."},{"name":"관리자 / 건강샵","description":"관리자웹 건강샵 관리 메뉴(상품 관리 / 주문 관리 / 운영 설정). 앱 건강샵에 노출할 상품과 배송비 정책, 건강샵 주문 상태를 관리한다. SYSTEM_ADMIN 토큰 전용이며 쓰기 작업은 모두 감사기록을 남긴다."},{"name":"건강샵(앱)","description":"앱 건강샵 탭의 건강기능식품 판매. 상품·배송비 정책 조회와 주문 생성·내 주문 목록. 모두 회원 토큰 필요."},{"name":"관리자 / 코드관리","description":"관리자웹 [시스템 관리 > 코드관리] 메뉴. 처방전 상태·수령방식·택배사처럼 화면에 보이는 코드 이름과 정렬·사용여부를 운영자가 직접 관리한다. 코드값(code_value)은 백엔드 enum·DB 저장값과 1:1 이라 바꿀 수 없고, 표시 이름만 바뀌므로 이름을 고쳐도 기존 데이터와 로직은 그대로다. 조회는 관리자 토큰, 변경은 SYSTEM_ADMIN 토큰이 필요하다."},{"name":"관리자 / 대시보드","description":"관리자웹 홈(대시보드) 화면의 집계 1회 호출. 관리자 토큰 필요: SYSTEM_ADMIN 은 전체, PHARMACY_ADMIN 은 매핑된 소속 약국 기준으로 집계된다."},{"name":"약국(앱)","description":"앱 약국 찾기 화면용 공개 API. 약국 검색·상세와 비배송(산간) 지역 확인. 로그인 없이 호출 가능."}],"paths":{"/api/v1/shop/orders/create":{"post":{"tags":["건강샵(앱)"],"summary":"주문 생성","description":"앱 건강샵 결제가 끝난 뒤 호출한다. 서버는 결제를 검증하지 않으며 items 의 productId 로 상품을 다시 조회해 단가와 배송비(정책 기준)를 재계산한 뒤 결제 완료(PAID) 상태로 저장한다. 수량은 1~99 로 보정되고 없는 상품은 COMMON_003. 주문번호는 SO-YYYYMMDD-### 형식. 회원 토큰 필요.","operationId":"createOrder","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"items":[{"productId":"(상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식))","quantity":"(주문 수량 (1 이상))"}],"delivery":{"name":"(받는 분 이름)","phone":"(받는 분 연락처)","zipcode":"(선택 — 우편번호 (5자리))","address":"(배송 기본 주소)","detailAddress":"(선택 — 배송 상세 주소 (동/호수))","memo":"(선택 — 배송 요청사항)"}}},"sample":{"summary":"✅ 실제 값 예시","value":{"items":[{"productId":"HP-001","quantity":2}],"delivery":{"name":"홍길동","phone":"010-1234-5678","zipcode":48058,"address":"부산광역시 해운대구 센텀중앙로 79","detailAddress":"101동 1203호","memo":"부재 시 문 앞에 놓아주세요."}}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseOrderView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/unsubscribe":{"post":{"tags":["푸시(앱)"],"summary":"FCM 토큰 구독 해제","description":"앱 로그아웃 직전에 호출해 이 기기의 토큰(본문 fcmToken)을 구독 목록에서 지운다. 이후 이 기기로는 푸시가 오지 않는다. 회원 토큰 필요.","operationId":"unsubscribe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"fcmToken":"(해제할 FCM 디바이스 토큰 — 구독 시 전송한 값)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"fcmToken":"dXk9f3…:APA91bH…"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/subscribe":{"post":{"tags":["푸시(앱)"],"summary":"FCM 토큰 구독 등록/갱신","description":"앱이 로그인 후(FcmEffect) FCM 토큰을 얻을 때마다 호출한다. 같은 토큰이 이미 있으면 회원·기기(deviceId)·플랫폼(platform) 정보만 갱신한다. 푸시 발송 시 회원별로 가장 최근에 갱신된 토큰 1개(마지막 로그인 폰)에만 보내므로, 토큰이 바뀌면 반드시 다시 호출해야 한다. 회원 토큰 필요.","operationId":"subscribe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"fcmToken":"(Firebase Cloud Messaging 디바이스 토큰)","deviceId":"(선택 — 단말 식별자 (앱이 생성한 고유값))","platform":"(선택 — 단말 플랫폼 — android / ios)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"fcmToken":"dXk9f3…:APA91bH…","deviceId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","platform":"android"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseSubscriptionInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/send":{"post":{"tags":["푸시(앱)"],"summary":"푸시 수동 발송 (관리자)","description":"SYSTEM_ADMIN 토큰 전용. 관리자웹에 전용 메뉴는 없고 운영자가 직접 호출한다. memberId 를 주면 그 회원의 마지막 로그인 폰 1대에, 비우면 전체 회원(회원별 최신 토큰 1개씩)에 broadcast 한다. 메시지 이력을 먼저 저장한 뒤 FCM 으로 보내며 응답 {messageId} 는 그 이력 id. 감사기록 PUSH_SEND 를 남긴다.","operationId":"send","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memberId":"(선택 — 수신 회원 PK — GET /api/v1/admin/members 목록의 id, null = 전체 발송(broadcast))","title":"(알림 제목)","body":"(알림 본문)","payload":"(선택 — 앱 딥링크용 부가 데이터 (JSON 문자열))","relatedType":"(선택 — 연관 대상 유형 — order / delivery / eligibility / notice 등)","relatedId":"(선택 — 연관 대상 PK)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memberId":7,"title":"추석 연휴 배송 안내","body":"연휴 기간 택배 배송이 지연될 수 있습니다.","payload":{"screen":"NoticeDetail","id":15},"relatedType":"notice","relatedId":15}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringLong"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/messages/read":{"post":{"tags":["푸시(앱)"],"summary":"알림 1건 읽음 처리","description":"앱 알림 목록 화면(PushList)에서 항목을 열 때 호출한다. 대상은 본문 pushId. 타인의 메시지는 AUTH_005, 없으면 COMMON_003. 전체 공지도 읽음 처리할 수 있다. 회원 토큰 필요.","operationId":"markRead","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageReadRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pushId":"(알림 PK — GET /api/v1/push/messages 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pushId":88}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/messages/read-all":{"post":{"tags":["푸시(앱)"],"summary":"알림 전체 읽음 처리","description":"앱 알림 목록 화면(PushList)의 모두 읽음 버튼. 본인 미읽음 메시지를 한 번에 읽음 처리하고 처리 건수를 {updated} 로 돌려준다. 회원 토큰 필요.","operationId":"markAllRead","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringInteger"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/messages/delete":{"post":{"tags":["푸시(앱)"],"summary":"알림 1건 삭제","description":"앱 알림 목록 화면(PushList)의 삭제. 대상은 본문 pushId. 본인에게 온 메시지만 지울 수 있고 전체 공지(broadcast)나 타인 메시지는 AUTH_005. 회원 토큰 필요.","operationId":"deleteMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pushId":"(알림 PK — GET /api/v1/push/messages 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pushId":88}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/prescriptions":{"post":{"tags":["처방전·주문(앱)"],"summary":"처방전 등록 (약국 접수)","description":"앱 처방전 미리보기 화면(PrescPreview)에서 약국 선택까지 마친 뒤 호출한다. pharmacyCode(필수), receiveType(onLine 택배 / offLine 방문), 배송지 스냅샷, 업로드 이미지 경로, qrValue(필수), medicineSeq 를 한 번에 저장하며, 상태 01 발송으로 생성되고 약국명·전화·주소가 스냅샷으로 복사된다. 없는 약국 코드는 COMMON_003. 이 시점에는 푸시가 나가지 않는다. 회원 토큰 필요.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrescriptionRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(조제 요청 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))","receiveType":"(선택 — 수령 방식 — onLine 택배배송 / offLine 방문수령)","deliveryAddressId":"(선택 — 배송지 PK — GET /api/v1/addresses 의 deliveryAddressSeq, onLine 일 때)","deliveryName":"(선택 — 수령인 이름 (onLine 스냅샷))","deliveryPhone":"(선택 — 수령인 연락처 (onLine 스냅샷))","deliveryAddress":"(선택 — 배송 기본 주소 (onLine 스냅샷))","deliveryDetailAddress":"(선택 — 배송 상세 주소 (동/호수))","prescriptionImagePath":"(선택 — 처방전 이미지 저장 경로 — POST /api/v1/prescriptions/upload-image 응답의 storagePath)","qrImagePath":"(선택 — QR 영역 이미지 저장 경로 — upload-image 응답의 storagePath)","qrValue":"(처방전 QR 원문 (또는 OCR 식별값))","medicineSeq":"(선택 — 발급정보 PK — POST /api/v1/prescriptions/qr-callback 응답의 medicineSeq, null = 미인식)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-001","receiveType":"onLine","deliveryAddressId":12,"deliveryName":"홍길동","deliveryPhone":"010-1234-5678","deliveryAddress":"부산광역시 해운대구 센텀중앙로 79","deliveryDetailAddress":"101동 1203호","prescriptionImagePath":"C:/DEV/.../uploads/prescription/7/2026-09-11/3f9c1a2b__rx.jpg","qrImagePath":"C:/DEV/.../uploads/prescription/7/2026-09-11/3f9c1a2b__qr.jpg","qrValue":"PRS_ENC:9f3a2b1c…","medicineSeq":55}}},"example":null}},"required":true},"responses":{"200":{"description":"등록 성공 (상태 01 발송)","content":{"application/json":{"examples":{"택배 접수 직후":{"description":"택배 접수 직후","value":{"success":true,"data":{"id":42,"status":"01","statusName":"발송","receiveType":"onLine","qrValue":"OCR","prescriptionImageUrl":"/uploads/prescription/12/2026-09-11/3f2a9c__rx.jpg","pharmacyName":"약나루약국","pharmacyPhone":"02-1234-5678","pharmacyAddress":"서울특별시 강남구 테헤란로 123 1층","memId":"hong123","memName":"홍길동","deliveryName":"홍길동","deliveryPhone":"010-1234-5678","deliveryAddress":"서울특별시 서초구 반포대로 45","deliveryDetailAddress":"101동 202호","reqDate":"2026-09-11T10:15:30.123","medicineList":[{"drgCd":"641102470","drgNm":"타이레놀정500밀리그램"}],"partnerInfo":{"seq":16,"hospitalName":"서울내과의원","doctorName":"이의사","patientName":"홍길동","prescriptionDate":"2026-09-11"}}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/prescriptions/upload-image":{"post":{"tags":["처방전·주문(앱)"],"summary":"처방전 이미지 업로드","description":"앱 처방전 미리보기 화면(PrescPreview)에서 촬영본을 먼저 올릴 때 호출한다. multipart 파트명은 file, 허용 형식 jpeg/png/pdf, 최대 20MB. 응답의 storagePath 를 처방전 등록 요청의 prescriptionImagePath 로 그대로 전달한다. 파일만 저장하고 DB 레코드는 만들지 않는다. 회원 토큰 필요.","operationId":"upload","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"처방전 이미지 파일 (jpeg/png/pdf, 20MB 이하)"}},"required":["file"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUploadImageResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/prescriptions/update-status":{"post":{"tags":["처방전·주문(앱)"],"summary":"처방전 상태 변경 (회원)","description":"앱 주문 진행 화면(MedicineOrder)과 결제 화면(MedicineOrderNicePay)에서 회원 측 상태 전이(예: 결제 완료 후 04, 수령 완료 010)에 호출한다. 대상은 본문 prescriptionId 이며 본인 처방전만 가능(아니면 AUTH_005). status 는 상태코드 문자열이고 알 수 없는 코드는 COMMON_001. 03 조제불가로 바꿀 때만 unavailableReason 이 저장된다. 회원이 바꾼 상태는 푸시를 발송하지 않는다(푸시는 관리자 처방전 갱신에서만). 회원 토큰 필요.","operationId":"changeStatus","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeStatusRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"prescriptionId":"(대상 처방전(주문) PK — GET /api/v1/orders 의 prescriptionSeq)","status":"(변경할 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료)","unavailableReason":"(선택 — 조제불가 사유 — status=03 일 때)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"prescriptionId":101,"status":"010","unavailableReason":"재고 부족"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/prescriptions/qr-callback":{"post":{"tags":["처방전·주문(앱)"],"summary":"처방전 인식 결과 저장 (OCR 콜백)","description":"앱 처방전 미리보기 화면(PrescPreview)에서 CLOVA OCR 로 파싱한 결과(ocr: 교부번호·환자·병원·의사·교부일·약품코드)를 보내면 처방전 발급 정보를 저장하고 medicineSeq 를 돌려준다. 이 값을 처방전 등록 요청의 medicineSeq 로 전달해야 상세에 약품 목록과 병원 정보가 붙는다. 약품명은 OCR 인식값을 쓰지 않고 약품코드로 약품 마스터(없으면 대체약품 자료)를 조회해 채운다. prsEnc(QR) 경로는 EDB 연동 중단으로 현재 사용하지 않으며, ocr 이 없으면 success=false 로 응답한다. 회원 토큰 필요.","operationId":"qrCallback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QrCallbackRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"prsEnc":"(선택 — 처방전 QR 암호문 (구 EDB QR 방식) — 현재 미사용)","ocr":{"issueNo":"(선택 — 처방전 교부번호)","patientName":"(선택 — 환자 성명)","hospitalName":"(선택 — 의료기관 명칭)","doctorName":"(선택 — 처방 의사 성명)","prescriptionDate":"(선택 — 교부일 (YYYY-MM-DD))","medicines":[{"code":"(약품 코드 (EDI 보험코드 9자리))","name":"(선택 — 약품명 (인접 텍스트 기반 추정))"}]}}},"sample":{"summary":"✅ 실제 값 예시","value":{"prsEnc":"PRS_ENC:9f3a2b1c…","ocr":{"issueNo":"2026-0911-00042","patientName":"홍길동","hospitalName":"부산대학교병원","doctorName":"김의사","prescriptionDate":"2026-09-11","medicines":[{"code":640007270,"name":"타이레놀정500mg"}]}}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseQrCallbackResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/pharmacist/signup":{"post":{"tags":["약사 회원가입"],"summary":"약사 회원가입 신청","description":"관리자웹 회원가입 화면(signup)에서 호출한다. multipart 로 payload(약사·약국·계좌 정보 JSON 문자열)와 businessLicense(사업자등록증 파일, 필수)를 보낸다. 한 트랜잭션으로 약사 계정(PHARMACY_ADMIN, 상태 PENDING) + 약국(코드 PH-### 자동 채번, 배송 가능 Y 로 즉시 앱 약국 목록에 노출) + 약사-약국 매핑 + 사업자등록증 첨부를 만든다. 아이디 중복이나 payload 형식 오류, 파일 누락은 COMMON_001. PENDING 동안 로그인은 AUTH_005 로 거절되며 운영자가 /api/v1/admin/pharmacies/approve 로 승인하면 ACTIVE 가 된다. 로그인 불필요.","operationId":"signUp","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"payload":{"type":"string","description":"PharmacistSignUpRequest 를 JSON 문자열로 직렬화한 값 (adminId, adminPass, adminName, adminEmail, adminTel, pharmacyName, alarmPhone, pharmacyAddress, pharmacistName, pharmacistPhone, licenseNum, businessNum, accountBankName, accountBankNumber, accountOwner 필수)"},"businessLicense":{"type":"string","format":"binary","description":"사업자등록증 파일 (필수)"}},"required":["payload"]}}}},"responses":{"200":{"description":"신청 접수 (검토 대기)","content":{"application/json":{"examples":{"접수 완료":{"description":"접수 완료","value":{"success":true,"data":{"adminUserId":31,"pharmacyCode":"PH-012","adminId":"pharm_kim","pharmacyName":"약나루약국","state":"PENDING"}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacistSignUpResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/pharmacies/check-delivery":{"post":{"tags":["약국(앱)"],"summary":"비배송 지역 확인","description":"앱 배송지 관리 화면(AddressManagement)에서 배송지 저장 전에 호출한다. 우편번호(zonecode, 필수) 또는 도로명(roadname) 중 하나라도 비배송 지역 목록과 일치하면 deliveryYn=N 과 사유(reason)를 돌려주고, 둘 다 아니면 deliveryYn=Y. 로그인 불필요.","operationId":"checkDelivery","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckDeliveryRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"zonecode":"(우편번호 (5자리) — 비배송 우편번호 목록과 대조)","roadname":"(선택 — 도로명 — 비배송 도로명 목록과 부분 일치 대조)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"zonecode":48058,"roadname":"센텀중앙로"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCheckDeliveryResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/signup":{"post":{"tags":["회원(앱)"],"summary":"회원가입","description":"앱 회원가입 정보 입력 화면(SignUpInfo)에서 호출한다. 이메일 중복은 MEMBER_002, 본인인증 DI 중복은 MEMBER_003 으로 거절되며, 아이디 중복은 사전에 check-id 로 확인해야 한다. 현재는 memId/memPass/memEmail/memName 만 저장되고 생년월일·성별·전화·추천인은 저장되지 않으므로 필요하면 가입 후 내 정보 수정으로 보완한다. 가입 즉시 로그인과 같은 토큰 쌍을 돌려준다. 로그인 불필요.","operationId":"signUp_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memId":"(로그인 아이디 (4~64자, 중복 불가 — POST /api/v1/members/check-id 로 사전 확인))","memPass":"(비밀번호 (8~64자))","memEmail":"(이메일 (중복 불가 — POST /api/v1/members/check-email 로 사전 확인))","memName":"(회원 이름)","memBirth":"(선택 — 생년월일 (YYYY-MM-DD))","memGender":"(선택 — 성별 코드 — 0 남성 / 1 여성)","memTel":"(선택 — 휴대폰 번호)","memDi":"(선택 — 본인인증(NICE) DI 값 — 중복 가입 차단 키, POST /api/v1/members/check-di 로 사전 확인)","memRecommend":"(선택 — 추천인 회원 PK (97593712 − 추천인 코드) — 현재 서버에서 저장하지 않는 예약 필드)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memId":"hong1234","memPass":"********","memEmail":"hong@example.com","memName":"홍길동","memBirth":"1960-05-20","memGender":0,"memTel":"010-1234-5678","memDi":"MC0GCCqGSIb3DQIJAyEA3f9a…","memRecommend":3}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseTokenResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/password":{"post":{"tags":["회원(앱)"],"summary":"비밀번호 재설정 (임시 비밀번호 메일)","description":"앱 비밀번호 찾기 화면(ResetPassword)에서 호출한다. 아이디(memId)와 등록 이메일(memEmail)이 일치하면 12자 임시 비밀번호로 바꾸고 그 이메일로 발송한다. 없는 아이디는 MEMBER_001, 이메일 불일치는 AUTH_002, 메일 발송 실패 시 비밀번호 변경도 롤백되고 COMMON_004. 로그인 불필요.","operationId":"resetPassword","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memId":"(로그인 아이디)","memEmail":"(계정에 등록된 이메일 — 아이디와 일치해야 발송)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memId":"hong1234","memEmail":"hong@example.com"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/me/withdraw":{"post":{"tags":["회원(앱)"],"summary":"회원 탈퇴","description":"앱 탈퇴 확인 화면(WithdrawConfirm)에서 호출한다. 회원 상태를 WITHDRAWN 으로 바꾸고 soft delete 처리하며, 이후 로그인은 MEMBER_004 로 거절된다. 되돌릴 수 없다. 회원 토큰 필요.","operationId":"withdraw","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me/update":{"post":{"tags":["회원(앱)"],"summary":"내 정보 수정","description":"앱 내 정보 수정 화면(EditProfile)에서 호출한다. 이메일·전화·우편번호·주소만 바꿀 수 있고 null 로 보낸 항목은 유지된다. 이메일을 바꾸면 다른 회원과 중복인지 검사해 MEMBER_002 로 거절한다. 회원 토큰 필요.","operationId":"updateProfile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memEmail":"(선택 — 이메일 — null = 미변경)","memTel":"(선택 — 휴대폰 번호 — null = 미변경)","memZipcode":"(선택 — 우편번호 (5자리) — null = 미변경)","memAddr1":"(선택 — 기본 주소 — null = 미변경)","memAddr2":"(선택 — 상세 주소 — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memEmail":"hong@example.com","memTel":"010-1234-5678","memZipcode":48058,"memAddr1":"부산광역시 해운대구 센텀중앙로 79","memAddr2":"101동 1203호"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMemberInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me/update-push":{"post":{"tags":["회원(앱)"],"summary":"광고성 푸시 수신동의 설정","description":"앱 더보기(More)의 수신동의 토글과 회원가입 직후(SignUpInfo)에 호출한다. memPush 는 Y 또는 N. 이 값은 마케팅 수신 여부만 기록하며 주문·심사 결과 같은 서비스 푸시 발송을 막지는 않는다. 회원 토큰 필요.","operationId":"setPushAgree","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPushAgreeRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memPush":"(푸시 수신 동의 — Y 동의 / N 거부)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memPush":"Y"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me/update-password":{"post":{"tags":["회원(앱)"],"summary":"비밀번호 변경","description":"앱 비밀번호 변경 화면(ChangePassword)에서 호출한다. 현재 비밀번호(oldPass)가 맞아야 하며 틀리면 AUTH_002. 새 비밀번호는 8~64자. 회원 토큰 필요.","operationId":"changePassword","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"oldPass":"(현재 비밀번호)","newPass":"(새 비밀번호 (8~64자))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"oldPass":"********","newPass":"********"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me/update-notify":{"post":{"tags":["회원(앱)"],"summary":"알림 수신 설정","description":"앱 더보기(More) 의 [푸시 알림] 스위치. memNotify 는 Y 또는 N. N 이면 주문·배송 같은 서비스 알림의 휴대폰 푸시를 보내지 않는다. 앱 안 알림함 기록은 그대로 남아 나중에 켜면 지난 내용을 볼 수 있다. 광고성 정보 수신동의(/me/update-push)와는 별개 값이다. 회원 토큰 필요.","operationId":"setNotifyAgree","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetNotifyRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memNotify":"(알림 받기 — Y 받음 / N 받지 않음)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memNotify":"Y"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me/register-fcm":{"post":{"tags":["회원(앱)"],"summary":"FCM 토큰 회원 레코드에 저장","description":"회원 레코드에 최신 FCM 토큰을 보관한다. 실제 푸시 발송 대상은 /api/v1/push/subscribe 로 등록한 구독 정보를 기준으로 고르므로, 앱은 subscribe 를 반드시 함께 호출해야 한다. 회원 토큰 필요.","operationId":"registerFcm","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FcmTokenRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"fcmToken":"(Firebase Cloud Messaging 디바이스 토큰)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"fcmToken":"dXk9f3…:APA91bH…"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/check-recommend":{"post":{"tags":["회원(앱)"],"summary":"추천인 코드 유효 확인","description":"앱 회원가입 정보 입력 화면(SignUpInfo)에서 추천인 코드를 입력했을 때 호출한다. 코드를 회원번호로 환산해 해당 회원이 존재하면 {valid:true}. 숫자가 아닌 코드는 서버 오류(COMMON_002)가 나므로 앱에서 숫자만 보낸다. 로그인 불필요.","operationId":"checkRecommend","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckRecommendRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"code":"(추천인 코드 (숫자) — 97593712 − 추천인 회원 PK 로 생성, 해당 회원 존재 시 valid=true)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"code":97593709}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringBoolean"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/check-id":{"post":{"tags":["회원(앱)"],"summary":"회원 아이디 중복 확인","description":"앱 회원가입 정보 입력 화면(SignUpInfo)의 중복확인 버튼. 사용 가능하면 {available:true}, 빈 값이면 false. 로그인 불필요.","operationId":"checkId","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckIdRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memId":"(확인할 로그인 아이디)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memId":"hong1234"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringBoolean"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/check-email":{"post":{"tags":["회원(앱)"],"summary":"이메일 중복 확인","description":"앱 회원가입 화면과 내 정보 수정 화면(EditProfile)에서 호출한다. 사용 가능하면 {available:true}. 로그인 불필요.","operationId":"checkEmail","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckEmailRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memEmail":"(확인할 이메일)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memEmail":"hong@example.com"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringBoolean"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/members/check-di":{"post":{"tags":["회원(앱)"],"summary":"본인인증 DI 중복 확인","description":"NICE 본인인증을 마친 뒤 그 DI(memDi)로 이미 가입된 회원이 있는지 확인한다. 가입 가능하면 {available:true}. 로그인 불필요.","operationId":"checkDi","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckDiRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memDi":"(본인인증(NICE) DI 값)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memDi":"MC0GCCqGSIb3DQIJAyEA3f9a…"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringBoolean"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/eligibility/reject":{"post":{"tags":["자격 심사(앱)"],"summary":"자격 반려 (관리자)","description":"관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 전용. 대상은 본문 eligibilityId, reason 을 비우면 '사유 미입력' 으로 저장된다. 상태를 R(반려)로 바꾸고 신청 회원에게 FCM 푸시(약 배송 자격 반려, payload 에 reason)를 보내며 감사기록 ELIGIBILITY_REJECT 를 남긴다. 관리자웹 약 배송 자격 메뉴는 같은 동작의 /api/v1/admin/eligibility/reject 를 호출한다.","operationId":"reject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"eligibilityId":"(반려 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id)","reason":"(선택 — 반려 사유 — 회원 앱에 rejectDesc 로 노출)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"eligibilityId":21,"reason":"서류 식별이 불가하여 재제출이 필요합니다."}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilitySummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/eligibility/documents":{"post":{"tags":["자격 심사(앱)"],"summary":"자격 신청 (서류 업로드)","description":"앱 약 배송 자격 화면(DeliveryEligibility)에서 호출한다. multipart 로 documentTypes(카테고리 코드 1개: ltc65plus 65세 이상 장기요양등급자 / disabled 장애인 / infectiousDisease 감염병 환자 / rareDisease 희귀질환자)와 files(1개 이상, jpg/jpeg/gif/png/pdf, 각 20MB 이하)를 보낸다. 심사중(I) 상태의 신청 1건이 새로 만들어지며 이전 신청을 덮어쓰지 않는다. 회원 토큰 필요.","operationId":"submit","parameters":[{"name":"documentTypes","in":"query","description":"카테고리 코드: ltc65plus | disabled | infectiousDisease | rareDisease","required":true,"schema":{"type":"string"},"example":"ltc65plus"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","description":"증빙 서류 파일 목록 (jpg/jpeg/gif/png/pdf, 각 20MB 이하)","items":{"type":"string","format":"binary"}}},"required":["files"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilityDetail"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/eligibility/approve":{"post":{"tags":["자격 심사(앱)"],"summary":"자격 승인 (관리자)","description":"관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 전용. 대상은 본문 eligibilityId. 상태를 S(승인)로 바꾸고 신청 회원에게 FCM 푸시(약 배송 자격 승인)를 보내며 감사기록 ELIGIBILITY_APPROVE 를 남긴다. 관리자웹 약 배송 자격 메뉴는 같은 동작의 /api/v1/admin/eligibility/approve 를 호출한다.","operationId":"approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"eligibilityId":"(승인 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"eligibilityId":21}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilitySummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/dev/reset-prescriptions":{"post":{"tags":["개발용(dev)"],"summary":"처방전 이력 전체 삭제","description":"개발자가 테스트 데이터를 비울 때 직접 호출한다. order_info(처방전/주문), issue_drug(인식 약품), issue_info(처방전 인식 정보) 테이블을 FK 순서대로 모두 DELETE 하고 테이블별 삭제 건수를 돌려준다. 되돌릴 수 없다. 로그인 불필요.","operationId":"resetPrescriptions","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringInteger"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/dev/reset-eligibility":{"post":{"tags":["개발용(dev)"],"summary":"약 배송 자격 이력 전체 삭제","description":"개발자가 테스트 데이터를 비울 때 직접 호출한다. eligibility_file(첨부 서류)과 eligibility_info(자격 신청)를 모두 DELETE 하고 테이블별 삭제 건수를 돌려준다. 업로드된 실제 파일은 지우지 않는다. 되돌릴 수 없다. 로그인 불필요.","operationId":"resetEligibility","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringInteger"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/bbs/qnas":{"get":{"tags":["게시판(앱)"],"summary":"내 Q&A 목록","description":"앱 문의 내역 화면(QnaList)에서 호출한다. 본인이 작성한 문의만 페이징하며 status 는 한글 라벨(답변대기/답변완료)이다. 회원 토큰 필요.","operationId":"myQnas","parameters":[{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageQnaView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["게시판(앱)"],"summary":"Q&A 작성","description":"앱 문의 작성 화면(QnaWrite)에서 호출한다. question(2~4000자) 필수, categoryId 는 선택이며 없는 카테고리면 COMMON_001. 답변대기 상태로 저장되고, 관리자가 답변을 달면 회원에게 FCM 푸시(문의 답변 도착)가 온다. 회원 토큰 필요.","operationId":"writeQna","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QnaWriteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"categoryId":"(선택 — 문의 카테고리 PK — GET /api/v1/bbs/qna-form 의 카테고리 id)","question":"(문의 내용 (2~4000자))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"categoryId":3,"question":"배송이 며칠 걸리나요?"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseQnaView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/auth/refresh":{"post":{"tags":["인증(앱)"],"summary":"토큰 갱신","description":"앱 네트워크 계층이 access 토큰 만료(401)를 받으면 자동으로 호출한다. refresh 토큰을 검증해 새 access/refresh 토큰 쌍과 내 정보를 다시 발급한다. 위조되었거나 만료된 refresh 토큰은 AUTH_004. 로그인 불필요(본문 refreshToken 만 사용).","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"refreshToken":"(갱신 토큰 — POST /api/v1/auth/login 응답의 refreshToken)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"refreshToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJob25nMTIzNCIsInR5cCI6InJlZnJlc2gifQ.7LmP…"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseTokenResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/auth/logout":{"post":{"tags":["인증(앱)"],"summary":"로그아웃","description":"서버는 stateless JWT 라 아무 것도 저장하지 않고 성공만 돌려준다. 앱은 이 호출 후 로컬 토큰을 지우고, 기기 푸시를 끊으려면 /api/v1/push/unsubscribe 를 함께 호출한다. 로그인 불필요.","operationId":"logout","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/auth/login":{"post":{"tags":["인증(앱)"],"summary":"회원 로그인","description":"앱 로그인 화면(SignIn)과 생체인증/PIN 재로그인(BiometricAuth, PinInput)에서 호출한다. 아이디(memId)와 비밀번호(memPass)를 검증해 access 토큰(30분)과 refresh 토큰(14일), 내 정보(myInfo)를 함께 돌려준다. 아이디·비밀번호 불일치는 AUTH_002, 탈퇴 회원은 MEMBER_004. 로그인 불필요.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memId":"(회원 로그인 아이디 — 회원가입(POST /api/v1/members/signup) 시 지정)","memPass":"(비밀번호 (평문, TLS 구간 전송))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memId":"hong1234","memPass":"********"}}},"example":null}},"required":true},"responses":{"200":{"description":"로그인 성공","content":{"application/json":{"examples":{"성공":{"description":"성공","value":{"success":true,"data":{"tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMiIsInVzZXJUeXBlIjoiVVNFUiJ9.xxxxx","refreshToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMiIsInR5cCI6InJlZnJlc2gifQ.yyyyy","expiresIn":1800,"myInfo":{"id":12,"memId":"hong123","memEmail":"hong@example.com","memName":"홍길동","memBirth":"1990-01-15","memGender":"1","memTel":"010-1234-5678","memPush":"Y","memState":"ACTIVE","roles":["USER"]}}}}}}}},"401":{"description":"아이디 또는 비밀번호 불일치","content":{"application/json":{"examples":{"AUTH_002":{"description":"AUTH_002","value":{"success":false,"error":{"code":"AUTH_002","message":"아이디 또는 비밀번호가 일치하지 않습니다."}}}}}}},"403":{"description":"탈퇴한 회원","content":{"application/json":{"examples":{"MEMBER_004":{"description":"MEMBER_004","value":{"success":false,"error":{"code":"MEMBER_004","message":"탈퇴한 회원입니다."}}}}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/app/setting/update":{"post":{"tags":["앱 설정"],"summary":"앱 부팅 설정 갱신 (관리자)","description":"SYSTEM_ADMIN 토큰 전용. 관리자웹에 전용 메뉴는 없고 운영자가 직접 호출한다. 대상 플랫폼은 본문 platform(android | ios)이며 null 로 보낸 항목은 유지된다. 변경 전/후 값으로 감사기록 APP_SETTING_UPDATE 를 남긴다. 앱은 다음 부팅부터 새 값을 읽는다.","operationId":"update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"platform":"(대상 플랫폼 — android / ios)","up_bool":"(선택 — 강제 업데이트 사용 여부 — yes / no, null = 미변경)","up_build":"(선택 — 강제 업데이트 기준 빌드 번호 — null = 미변경)","up_img":"(선택 — 업데이트 안내 이미지 URL — null = 미변경)","up_img_width":"(선택 — 업데이트 안내 이미지 가로 (px) — null = 미변경)","up_img_height":"(선택 — 업데이트 안내 이미지 세로 (px) — null = 미변경)","agree_bool":"(선택 — 약관 재동의 강제 여부 — yes / no, null = 미변경)","agree_no":"(선택 — 재동의가 필요한 약관 버전 번호 — null = 미변경)","popup_bool":"(선택 — 팝업 노출 여부 — yes / no, null = 미변경)","popup_img":"(선택 — 팝업 이미지 URL — null = 미변경)","server_bool":"(선택 — 서버 점검 중 여부 — yes / no, null = 미변경)","server_img":"(선택 — 점검 안내 이미지 URL — null = 미변경)","server_img_width":"(선택 — 점검 안내 이미지 가로 (px) — null = 미변경)","server_img_height":"(선택 — 점검 안내 이미지 세로 (px) — null = 미변경)","ocr_bool":"(선택 — 처방전 OCR 사용 여부 — yes / no, null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"platform":"android","up_bool":"no","up_build":12,"up_img":"https://cdn.yaknaru.co.kr/app/update.png","up_img_width":720,"up_img_height":1280,"agree_bool":"no","agree_no":2,"popup_bool":"no","popup_img":"https://cdn.yaknaru.co.kr/app/popup.png","server_bool":"no","server_img":"https://cdn.yaknaru.co.kr/app/maint.png","server_img_width":720,"server_img_height":1280,"ocr_bool":"no"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAppSettingView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/settings/update":{"post":{"tags":["관리자 / 건강샵"],"summary":"운영 설정 수정 (배송비 정책)","description":"관리자웹 운영 설정 메뉴의 저장 버튼. deliveryFee(기본 배송비), freeThreshold(무료배송 기준 금액) 중 보낸 항목만 바꾸며 음수는 COMMON_001. 이후 생성되는 주문부터 새 배송비가 적용된다. 변경 전/후 값으로 감사기록 SHOP_SETTING_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateSettings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"deliveryFee":"(선택 — 기본 배송비 (원) — null = 미변경)","freeThreshold":"(선택 — 무료 배송 기준 주문 금액 (원) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"deliveryFee":3000,"freeThreshold":30000}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseSettingView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/products/update":{"post":{"tags":["관리자 / 건강샵"],"summary":"상품 수정","description":"관리자웹 상품 관리 메뉴의 수정 모달. 대상은 본문 productCode(HP-###, 없거나 삭제된 상품은 COMMON_003). 보낸 항목만 바꾸고 null 은 유지하며 정가 > 판매가 검증은 수정 후 값 기준으로 다시 한다. visible=false 로 두면 앱 목록에서 즉시 사라진다. 감사기록 SHOP_PRODUCT_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"update_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"productCode":"(대상 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식))","category":"(선택 — 상품 카테고리명 — null = 미변경)","emoji":"(선택 — 카테고리 대표 이모지 — null = 미변경)","name":"(선택 — 상품명 — null = 미변경)","brand":"(선택 — 브랜드명 — null = 미변경)","brief":"(선택 — 한 줄 소개 — null = 미변경)","price":"(선택 — 판매가 (원) — null = 미변경)","originalPrice":"(선택 — 할인 전 정가 (원) — null = 미변경)","badge":"(선택 — 뱃지 — BEST / NEW, null = 미변경)","visible":"(선택 — 앱 노출 여부 — null = 미변경)","functionality":"(선택 — 기능성 내용 — null = 미변경)","intake":"(선택 — 섭취 방법 — null = 미변경)","caution":"(선택 — 섭취 시 주의사항 — null = 미변경)","image":"(선택 — 대표 이미지 (URL 또는 data URI) — null = 미변경)","detailImages":["(선택 — 상세 이미지 목록 — null = 미변경)"]}},"sample":{"summary":"✅ 실제 값 예시","value":{"productCode":"HP-001","category":"비타민","emoji":"🍊","name":"멀티비타민 미네랄 90정","brand":"약나루 헬스","brief":"하루 1정으로 챙기는 12종 비타민 + 8종 미네랄","price":24900,"originalPrice":32000,"badge":"BEST","visible":true,"functionality":"비타민 A·C·D·E 등 12종 비타민 보충","intake":"1일 1회, 1회 1정을 물과 함께 섭취","caution":"특정 질환이 있거나 의약품 복용 시 전문가와 상담 후 섭취하세요.","image":"https://cdn.yaknaru.co.kr/shop/HP-001.png","detailImages":["https://cdn.yaknaru.co.kr/shop/HP-001_1.png"]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseProductView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/products/delete":{"post":{"tags":["관리자 / 건강샵"],"summary":"상품 삭제","description":"관리자웹 상품 관리 메뉴의 삭제 버튼. 대상은 본문 productCode. soft delete 라 앱·관리자 목록에서 사라지지만 기존 주문의 상품 스냅샷에는 영향이 없다. 감사기록 SHOP_PRODUCT_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"productCode":"(삭제 대상 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"productCode":"HP-001"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/products/create":{"post":{"tags":["관리자 / 건강샵"],"summary":"상품 등록","description":"관리자웹 상품 관리 메뉴의 등록 모달. category, name, price 필수. 상품 코드는 HP-### 로 자동 채번되고 visible 을 비우면 노출된다. 정가(originalPrice)는 할인 표시용이라 판매가(price)보다 커야 하며 아니면 COMMON_001. 감사기록 SHOP_PRODUCT_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"category":"(상품 카테고리명)","emoji":"(선택 — 카테고리 대표 이모지)","name":"(상품명)","brand":"(선택 — 브랜드명)","brief":"(선택 — 한 줄 소개)","price":"(판매가 (원))","originalPrice":"(선택 — 할인 전 정가 (원) — null = 할인 없음)","badge":"(선택 — 뱃지 — BEST / NEW)","visible":"(선택 — 앱 노출 여부 — null = true)","functionality":"(선택 — 기능성 내용 (줄바꿈 구분))","intake":"(선택 — 섭취 방법)","caution":"(선택 — 섭취 시 주의사항)","image":"(선택 — 대표 이미지 (URL 또는 data URI))","detailImages":["(선택 — 상세 이미지 목록 (URL 또는 data URI))"]}},"sample":{"summary":"✅ 실제 값 예시","value":{"category":"비타민","emoji":"🍊","name":"멀티비타민 미네랄 90정","brand":"약나루 헬스","brief":"하루 1정으로 챙기는 12종 비타민 + 8종 미네랄","price":24900,"originalPrice":32000,"badge":"BEST","visible":true,"functionality":"비타민 A·C·D·E 등 12종 비타민 보충","intake":"1일 1회, 1회 1정을 물과 함께 섭취","caution":"특정 질환이 있거나 의약품 복용 시 전문가와 상담 후 섭취하세요.","image":"https://cdn.yaknaru.co.kr/shop/HP-001.png","detailImages":["https://cdn.yaknaru.co.kr/shop/HP-001_1.png"]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseProductView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/orders/update-status":{"post":{"tags":["관리자 / 건강샵"],"summary":"건강샵 주문 상태 변경","description":"관리자웹 건강샵 주문 관리 메뉴의 상태 변경. 대상은 본문 orderNo, status 는 PAID(결제 완료) / SHIPPING(배송 중) / DELIVERED(배송 완료) 중 하나(그 외는 COMMON_001). 상태 순서 검증이나 회원 푸시는 없다. 감사기록 SHOP_ORDER_STATUS_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateOrderStatus","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"orderNo":"(대상 주문번호 — GET /api/v1/admin/shop/orders 의 id (SO-YYYYMMDD-### 형식))","status":"(변경할 상태 코드 — PAID 결제 완료 / SHIPPING 배송 중 / DELIVERED 배송 완료)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"orderNo":"SO-20260911-001","status":"SHIPPING"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseOrderView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/roles/menus/update":{"post":{"tags":["관리자 / 메뉴·권한관리"],"summary":"권한별 메뉴 저장","description":"보낸 menuCodes 목록으로 그 권한의 허용 메뉴를 통째로 교체한다(체크 해제분은 자동 삭제). 없는 메뉴코드가 섞이면 COMMON_001. 저장 뒤 해당 권한 사용자가 다시 로그인하거나 화면을 새로 고치면 반영된다. 감사기록 ROLE_MENU_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateRoleMenu","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleMenuUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"roleCode":"(권한 코드)","menuCodes":["(허용할 메뉴코드 목록 — 빈 배열이면 모든 메뉴 차단)"]}},"sample":{"summary":"✅ 실제 값 예시","value":{"roleCode":"PHARMACY_ADMIN","menuCodes":["prescriptionMgt","myProfile"]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseRoleMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/prescriptions/update":{"post":{"tags":["관리자 / 처방전"],"summary":"처방전 갱신 (상태·가격·메모·송장)","description":"관리자웹 처방전 관리 상세 모달의 저장/상태 변경 버튼. 대상은 본문 prescriptionId. status(상태코드), 조제비·배송비, 복약안내(medicineDirection), 송장번호·택배사, 조제불가 사유, 약사 내부 메모(pharmacistMemo, 회원 미노출)를 부분 수정하며 null 은 유지. status 가 실제로 바뀌면 회원에게 FCM 푸시가 자동 발송된다(02 조제가능·03 조제불가·04 결제완료·05 조제완료·06 배송중·07 배송완료·010 수령완료). 알 수 없는 코드는 COMMON_001. 변경 전/후 값으로 감사기록 PRESCRIPTION_UPDATE. 관리자 토큰 필요(소속 약국 밖은 AUTH_005).","operationId":"update_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUpdatePrescriptionRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"prescriptionId":"(대상 처방전(주문) PK — GET /api/v1/admin/prescriptions 목록의 id)","status":"(선택 — 변경할 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료, null = 미변경)","prescriptionPrice":"(선택 — 약제비 (원) — null = 미변경)","deliveryPrice":"(선택 — 배송비 (원) — null = 미변경)","medicineDirection":"(선택 — 약사 복약 안내 (회원 노출) — null = 미변경)","deliveryNumber":"(선택 — 택배 송장번호 — 배송중(06) 전환 시 입력, null = 미변경)","deliveryCompany":"(선택 — 택배사명 (CJ대한통운/우체국 등) — 배송중(06) 전환 시 입력, null = 미변경)","unavailableReason":"(선택 — 조제불가 사유 — status=03 일 때, null = 미변경)","pharmacistMemo":"(선택 — 약사 내부 메모 (회원 미노출) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"prescriptionId":101,"status":"06","prescriptionPrice":12500,"deliveryPrice":3000,"medicineDirection":"식후 30분에 1정씩 복용하세요.","deliveryNumber":6889012345678,"deliveryCompany":"CJ대한통운","unavailableReason":"재고 부족","pharmacistMemo":"재고 확인 필요"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/prescriptions/update-partner-info":{"post":{"tags":["관리자 / 처방전"],"summary":"처방전 인식 정보 수정 (OCR 보정)","description":"관리자웹 처방전 관리 상세 모달에서 OCR 오인식된 병원·의사·환자·진단코드·교부일·약품을 약사가 바로잡을 때 호출한다. 대상은 본문 prescriptionId. 모든 필드는 보낸 값 그대로 저장되고(빈 문자열은 null), 인식 정보가 없던 처방전이면 ADMIN 유형으로 새로 만들어 연결한다. medicines 를 리스트로 보내면 기존 약품을 전부 교체하며(null 이면 유지) 약품명은 보낸 값을 무시하고 코드로 약품 마스터를 조회해 채운다. 푸시는 없다. 감사기록 PRESCRIPTION_PARTNER_INFO_UPDATE. 관리자 토큰 필요.","operationId":"updatePartnerInfo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUpdatePartnerInfoRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"prescriptionId":"(대상 처방전(주문) PK — GET /api/v1/admin/prescriptions 목록의 id)","hospitalName":"(선택 — 의료기관 명칭)","hospitalPhone":"(선택 — 의료기관 전화번호)","doctorName":"(선택 — 처방 의사 성명)","doctorLicenseNo":"(선택 — 의사 면허번호)","patientName":"(선택 — 환자 성명)","departmentCode":"(선택 — 진료과목 코드)","diagnosisCode1":"(선택 — 주상병 코드 (KCD))","diagnosisCode2":"(선택 — 부상병 코드 (KCD))","prescriptionDate":"(선택 — 처방전 교부일 (YYYY-MM-DD))","useDays":"(선택 — 처방전 사용기간 (일))","medicines":[{"code":"(약품 코드 (EDI 보험코드 9자리))","name":"(선택 — 약품명)","dosage":"(선택 — 1회 투약량)","daysTotal":"(선택 — 총 투약 일수)"}]}},"sample":{"summary":"✅ 실제 값 예시","value":{"prescriptionId":101,"hospitalName":"부산대학교병원","hospitalPhone":"051-240-7000","doctorName":"김의사","doctorLicenseNo":98765,"patientName":"홍길동","departmentCode":"01","diagnosisCode1":"J06.9","diagnosisCode2":"R50.9","prescriptionDate":"2026-09-11","useDays":3,"medicines":[{"code":640007270,"name":"타이레놀정500mg","dosage":1,"daysTotal":3}]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/update":{"post":{"tags":["관리자 / 약국"],"summary":"약국 정보 수정","description":"관리자웹 약국 관리 상세 모달의 저장 버튼. 대상은 본문 pharmacyCode(없으면 COMMON_003). 기본 정보·배송 가능 여부·약사/계좌 정보·영업시간·수수료·검토 메모를 부분 수정하며 null 은 유지. 여기서는 지오코딩을 하지 않으므로 주소를 바꾸면 gpsLat/gpsLon 도 함께 보내야 한다. 변경 전/후 값으로 감사기록 PHARMACY_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"update_3","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))","pharmacyName":"(선택 — 약국명 — null = 미변경)","pharmacyPhone":"(선택 — 약국 대표 전화 — null = 미변경)","zipcode":"(선택 — 우편번호 (5자리) — null = 미변경)","address":"(선택 — 약국 기본 주소 — null = 미변경)","detailAddress":"(선택 — 약국 상세 주소 — null = 미변경)","gpsLat":"(선택 — 위도 (WGS84) — null = 미변경)","gpsLon":"(선택 — 경도 (WGS84) — null = 미변경)","deliveryYn":"(선택 — 택배 배송 지원 여부 — Y / N, null = 미변경)","alarmPhone":"(선택 — 처방전 접수 알림 수신 전화번호 — null = 미변경)","pharmacistName":"(선택 — 약사 이름 — null = 미변경)","pharmacistPhone":"(선택 — 약사 전화번호 — null = 미변경)","licenseNum":"(선택 — 약사 면허번호 — null = 미변경)","businessNum":"(선택 — 사업자등록번호 — null = 미변경)","accountBankName":"(선택 — 정산 계좌 은행명 — null = 미변경)","accountBankNumber":"(선택 — 정산 계좌번호 — null = 미변경)","accountOwner":"(선택 — 정산 계좌 예금주 — null = 미변경)","openTimeMon":"(선택 — 월요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeTue":"(선택 — 화요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeWed":"(선택 — 수요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeThu":"(선택 — 목요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeFri":"(선택 — 금요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeSat":"(선택 — 토요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeSun":"(선택 — 일요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","pharmacyCharge":"(선택 — 플랫폼 중개 수수료율 (%) — null = 미변경)","reviewMemo":"(선택 — SYSTEM_ADMIN 검토 메모 — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-001","pharmacyName":"약나루약국 남구점","pharmacyPhone":"051-123-4567","zipcode":48434,"address":"부산광역시 남구 수영로 200","detailAddress":"1층 101호","gpsLat":35.1367,"gpsLon":129.0862,"deliveryYn":"Y","alarmPhone":"010-9876-5432","pharmacistName":"홍길동","pharmacistPhone":"010-1234-5678","licenseNum":12345,"businessNum":"123-45-67890","accountBankName":"부산은행","accountBankNumber":"101-2345-6789-01","accountOwner":"홍길동","openTimeMon":"09:00~18:00","openTimeTue":"09:00~18:00","openTimeWed":"09:00~18:00","openTimeThu":"09:00~18:00","openTimeFri":"09:00~18:00","openTimeSat":"09:00~13:00","openTimeSun":"휴무","pharmacyCharge":3.5,"reviewMemo":"사업자등록증 확인 완료"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/update-review-memo":{"post":{"tags":["관리자 / 약국"],"summary":"검토 메모 저장","description":"관리자웹 약국 관리 상세 모달의 검토 메모 저장 버튼. 대상은 본문 pharmacyCode. 운영자 내부 메모(reviewMemo)만 바꾸고 lastReviewedAt 이 갱신된다. 변경 전/후 값으로 감사기록 PHARMACY_REVIEW_MEMO_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateReviewMemo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyReviewMemoRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))","reviewMemo":"(선택 — 검토 메모 — null/공백 = 메모 삭제)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-001","reviewMemo":"사업자등록증 확인 완료"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/update-charge":{"post":{"tags":["관리자 / 약국"],"summary":"중개 수수료 저장","description":"관리자웹 약국 관리 상세 모달의 수수료 저장 버튼. 대상은 본문 pharmacyCode, pharmacyCharge 는 % 값이며 다른 항목은 건드리지 않는다. 변경 전/후 값으로 감사기록 PHARMACY_CHARGE_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateCharge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyChargeRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))","pharmacyCharge":"(선택 — 플랫폼 중개 수수료율 (%) — null = 미설정으로 저장)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-001","pharmacyCharge":3.5}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/reject":{"post":{"tags":["관리자 / 약국"],"summary":"약사 회원가입 반려","description":"관리자웹 약국 관리 상세 모달의 반려 버튼. 대상은 본문 pharmacyCode, reviewMemo(반려 사유)는 필수. 매핑된 PENDING 약사 계정을 모두 SUSPENDED 로 바꾸고(affectedAdminCount) 사유를 담은 반려 메일을 보낸다(메일 실패는 무시). 약국 레코드 자체는 삭제하지 않는다. 감사기록 PHARMACY_REJECT. SYSTEM_ADMIN 토큰 필요.","operationId":"reject_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyRejectRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — 약사 회원가입 응답의 pharmacyCode (PH-001 형식))","reviewMemo":"(반려 사유 (필수) — 약사에게 통보)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-006","reviewMemo":"사업자등록증 이미지가 식별되지 않습니다."}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminPharmacyReviewResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/create":{"post":{"tags":["관리자 / 약국"],"summary":"약국 등록","description":"관리자웹 약국 관리 메뉴의 신규 등록 모달에서 운영자가 직접 약국을 만들 때 호출한다(약사 회원가입 경로는 자동 채번). pharmacyCode 를 직접 지정하며 이미 있으면 COMMON_001. deliveryYn 은 Y/N(미지정 시 N), 영업시간 7종은 'HH:mm~HH:mm' 또는 '휴무'. 감사기록 PHARMACY_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"create_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(약국 코드 (PH-### 형식, 중복 불가))","pharmacyName":"(약국명)","pharmacyPhone":"(선택 — 약국 대표 전화)","zipcode":"(선택 — 우편번호 (5자리))","address":"(선택 — 약국 기본 주소)","detailAddress":"(선택 — 약국 상세 주소)","gpsLat":"(선택 — 위도 (WGS84))","gpsLon":"(선택 — 경도 (WGS84))","deliveryYn":"(선택 — 택배 배송 지원 여부 — Y / N, null = N)","openTimeMon":"(선택 — 월요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeTue":"(선택 — 화요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeWed":"(선택 — 수요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeThu":"(선택 — 목요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeFri":"(선택 — 금요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeSat":"(선택 — 토요일 영업시간 — HH:mm~HH:mm 또는 휴무)","openTimeSun":"(선택 — 일요일 영업시간 — HH:mm~HH:mm 또는 휴무)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-006","pharmacyName":"약나루약국 남구점","pharmacyPhone":"051-123-4567","zipcode":48434,"address":"부산광역시 남구 수영로 200","detailAddress":"1층 101호","gpsLat":35.1367,"gpsLon":129.0862,"deliveryYn":"Y","openTimeMon":"09:00~18:00","openTimeTue":"09:00~18:00","openTimeWed":"09:00~18:00","openTimeThu":"09:00~18:00","openTimeFri":"09:00~18:00","openTimeSat":"09:00~13:00","openTimeSun":"휴무"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/approve":{"post":{"tags":["관리자 / 약국"],"summary":"약사 회원가입 승인","description":"관리자웹 약국 관리 상세 모달의 승인 버튼. 대상은 본문 pharmacyCode. 이 약국에 매핑된 PENDING 약사 계정을 모두 ACTIVE 로 바꾸고(affectedAdminCount), 각 약사에게 승인 안내 메일을 보낸다(메일 실패는 무시). reviewMemo 를 주면 검토 메모도 저장한다. 감사기록 PHARMACY_APPROVE. SYSTEM_ADMIN 토큰 필요.","operationId":"approve_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyApproveRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — 약사 회원가입 응답의 pharmacyCode (PH-001 형식))","reviewMemo":"(선택 — 승인 시 남길 검토 메모)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-006","reviewMemo":"서류 확인 완료, 승인"}}},"example":null}},"required":true},"responses":{"200":{"description":"승인 처리 결과","content":{"application/json":{"examples":{"약사 1명 승인":{"description":"약사 1명 승인","value":{"success":true,"data":{"pharmacyCode":"PH-012","affectedAdminCount":1,"result":"APPROVED"}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminPharmacyReviewResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/menus/update":{"post":{"tags":["관리자 / 메뉴·권한관리"],"summary":"메뉴 수정","description":"메뉴명·경로·아이콘·상위메뉴·순서·사용여부를 바꾼다. 보낸 항목만 바뀌고 menuCode 는 바꿀 수 없다. 사용여부 N 이면 모든 권한의 사이드바에서 숨는다. 감사기록 MENU_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateMenu","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"menuId":"(수정할 메뉴 PK)","parentCode":"(선택 — 상위 메뉴코드 — 빈 문자열이면 최상위로)","menuName":"(선택 — 메뉴명)","menuPath":"(선택 — 이동 경로)","menuIcon":"(선택 — antd 아이콘 이름)","sortNo":"(선택 — 같은 레벨 안 순서)","useYn":"(선택 — 사용 여부 (Y/N))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"menuId":10,"parentCode":"sysMgt","menuName":"코드관리","menuPath":"/sysMgt/codeMgt","menuIcon":"SettingOutlined","sortNo":40,"useYn":"Y"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/menus/delete":{"post":{"tags":["관리자 / 메뉴·권한관리"],"summary":"메뉴 삭제","description":"하위 메뉴가 없는 메뉴만 지울 수 있다. 지우면 권한별 허용 설정에서도 함께 빠진다. 감사기록 MENU_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deleteMenu","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"menuId":"(삭제할 메뉴 PK)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"menuId":23}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/menus/create":{"post":{"tags":["관리자 / 메뉴·권한관리"],"summary":"메뉴 등록","description":"메뉴를 추가한다. menuCode 중복이거나 2단계를 넘기면 COMMON_001. 메뉴코드는 관리자웹 라우트 key 와 같아야 화면이 열린다. 감사기록 MENU_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createMenu","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"parentCode":"(선택 — 상위 메뉴코드 — 최상위면 비움)","menuCode":"(메뉴코드 — 관리자웹 라우트 key)","menuName":"(메뉴명)","menuPath":"(선택 — 이동 경로)","menuIcon":"(선택 — antd 아이콘 이름)","sortNo":"(선택 — 같은 레벨 안 순서)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"parentCode":"sysMgt","menuCode":"codeMgt","menuName":"코드관리","menuPath":"/sysMgt/codeMgt","menuIcon":"SettingOutlined","sortNo":40}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/members/update-state":{"post":{"tags":["관리자 / 회원"],"summary":"회원 상태 변경","description":"관리자웹 회원 관리(앱) 메뉴의 상세 모달에서 호출한다. 대상은 본문 memberId, state 는 ACTIVE / DORMANT / SUSPENDED / WITHDRAWN (대소문자 무관, 그 외는 COMMON_001). WITHDRAWN 으로 바꾸면 soft delete 도 함께 처리되어 회원은 더 이상 로그인할 수 없다. 변경 전/후 값으로 감사기록 MEMBER_STATE_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"changeState","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMemberStateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"memberId":"(대상 회원 PK — GET /api/v1/admin/members 목록의 id)","state":"(변경할 회원 상태 — ACTIVE 정상 / DORMANT 휴면 / SUSPENDED 정지 / WITHDRAWN 탈퇴)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"memberId":7,"state":"SUSPENDED"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminMemberSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/me/update":{"post":{"tags":["관리자 / 내 정보"],"summary":"내 정보 수정","description":"관리자웹 내 정보 메뉴의 수정 모달에서 호출한다. 이름·이메일·전화·생년월일만 바꿀 수 있고 null 로 보낸 항목은 유지된다. 변경 전/후 값으로 감사기록 ADMIN_ME_UPDATE 를 남긴다. 관리자 토큰 필요.","operationId":"updateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminName":"(선택 — 관리자 이름 (40자 이하) — null = 미변경)","adminEmail":"(선택 — 관리자 이메일 (120자 이하) — null = 미변경)","adminTel":"(선택 — 전화번호 (20자 이하) — null = 미변경)","adminBirth":"(선택 — 약사 생년월일 (YYYY-MM-DD) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminName":"홍길동","adminEmail":"pharm01@yaknaru.local","adminTel":"010-1234-5678","adminBirth":"1985-03-15"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMeInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/me/update-password":{"post":{"tags":["관리자 / 내 정보"],"summary":"내 비밀번호 변경","description":"관리자웹 내 정보 메뉴의 비밀번호 변경에서 호출한다. currentPassword 가 맞아야 하며 틀리면 AUTH_002. 새 비밀번호는 6~64자. 감사기록 ADMIN_ME_PASSWORD_UPDATE 를 남기되 비밀번호 값은 기록하지 않는다. 관리자 토큰 필요.","operationId":"changePassword_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"oldPass":"(현재 비밀번호)","newPass":"(새 비밀번호 (8~64자))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"oldPass":"********","newPass":"********"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/me/pharmacies/update":{"post":{"tags":["관리자 / 내 정보"],"summary":"내 약국 정보 수정","description":"관리자웹 약국정보 메뉴(pharmacyInfo)의 저장 버튼. 대상은 본문 pharmacyCode 이며 본인에게 매핑된 약국이 아니면 AUTH_005. null 로 보낸 항목은 유지된다. 주소(address)가 바뀌었는데 gpsLat/gpsLon 을 주지 않으면 카카오 지오코딩으로 위경도를 자동 산출한다. 영업시간은 요일별 'HH:mm~HH:mm' 또는 '휴무'. 감사기록 ADMIN_ME_PHARMACY_UPDATE 를 남긴다. 관리자 토큰 필요.","operationId":"updateMyPharmacy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPharmacyUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"pharmacyCode":"(대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))","pharmacyName":"(선택 — 약국명 — null = 미변경)","pharmacyPhone":"(선택 — 약국 대표 전화 — null = 미변경)","zipcode":"(선택 — 우편번호 (5자리) — null = 미변경)","address":"(선택 — 약국 기본 주소 — null = 미변경)","detailAddress":"(선택 — 약국 상세 주소 — null = 미변경)","gpsLat":"(선택 — 위도 (WGS84) — null = 미변경)","gpsLon":"(선택 — 경도 (WGS84) — null = 미변경)","deliveryYn":"(선택 — 택배 배송 지원 여부 — Y / N, null = 미변경)","alarmPhone":"(선택 — 처방전 접수 알림 수신 전화번호 — null = 미변경)","pharmacistName":"(선택 — 약사 이름 — null = 미변경)","pharmacistPhone":"(선택 — 약사 전화번호 — null = 미변경)","licenseNum":"(선택 — 약사 면허번호 — null = 미변경)","businessNum":"(선택 — 사업자등록번호 — null = 미변경)","accountBankName":"(선택 — 정산 계좌 은행명 — null = 미변경)","accountBankNumber":"(선택 — 정산 계좌번호 — null = 미변경)","accountOwner":"(선택 — 정산 계좌 예금주 — null = 미변경)","openTimeMon":"(선택 — 월요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeTue":"(선택 — 화요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeWed":"(선택 — 수요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeThu":"(선택 — 목요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeFri":"(선택 — 금요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeSat":"(선택 — 토요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","openTimeSun":"(선택 — 일요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경)","pharmacyCharge":"(선택 — 플랫폼 중개 수수료율 (%) — null = 미변경)","reviewMemo":"(선택 — SYSTEM_ADMIN 검토 메모 — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"pharmacyCode":"PH-001","pharmacyName":"약나루약국 남구점","pharmacyPhone":"051-123-4567","zipcode":48434,"address":"부산광역시 남구 수영로 200","detailAddress":"1층 101호","gpsLat":35.1367,"gpsLon":129.0862,"deliveryYn":"Y","alarmPhone":"010-9876-5432","pharmacistName":"홍길동","pharmacistPhone":"010-1234-5678","licenseNum":12345,"businessNum":"123-45-67890","accountBankName":"부산은행","accountBankNumber":"101-2345-6789-01","accountOwner":"홍길동","openTimeMon":"09:00~18:00","openTimeTue":"09:00~18:00","openTimeWed":"09:00~18:00","openTimeThu":"09:00~18:00","openTimeFri":"09:00~18:00","openTimeSat":"09:00~13:00","openTimeSun":"휴무","pharmacyCharge":3.5,"reviewMemo":"사업자등록증 확인 완료"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/eligibility/reject":{"post":{"tags":["관리자 / 자격 심사"],"summary":"자격 반려","description":"관리자웹 약 배송 자격 상세 모달의 반려 버튼. 대상은 본문 eligibilityId, reason 을 비우면 '사유 미입력' 으로 저장된다. 상태를 R 로 바꾸고 rejectDesc 에 사유를 남기며 신청 회원에게 FCM 푸시(약 배송 자격 반려, payload 에 reason)를 보낸다. 회원은 앱에서 재신청할 수 있다. 감사기록 ELIGIBILITY_REJECT. /api/v1/eligibility/reject 와 같은 동작. 관리자 토큰 필요.","operationId":"reject_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"eligibilityId":"(반려 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id)","reason":"(선택 — 반려 사유 — 회원 앱에 rejectDesc 로 노출)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"eligibilityId":21,"reason":"서류 식별이 불가하여 재제출이 필요합니다."}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilitySummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/eligibility/approve":{"post":{"tags":["관리자 / 자격 심사"],"summary":"자격 승인","description":"관리자웹 약 배송 자격 상세 모달의 승인 버튼. 대상은 본문 eligibilityId(없으면 COMMON_003). 상태를 S 로 바꾸고 신청 회원에게 FCM 푸시(약 배송 자격 승인)를 보내며 변경 전/후 값으로 감사기록 ELIGIBILITY_APPROVE 를 남긴다. /api/v1/eligibility/approve 와 같은 동작. 관리자 토큰 필요.","operationId":"approve_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"eligibilityId":"(승인 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"eligibilityId":21}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilitySummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/drug-master/upload":{"post":{"tags":["관리자 / 약품 마스터"],"summary":"약제급여목록표 엑셀 업로드 (전체 교체)","description":"관리자웹 약품 마스터 메뉴의 업로드 버튼. multipart 파트명 file 로 심평원 약제급여목록 및 급여상한금액표 엑셀을 올린다. 상단 30행에서 '제품코드'와 '제품명' 헤더 행을 자동으로 찾고(못 찾으면 COMMON_001), 제품코드가 9자리 숫자인 행만 적재하며 중복 코드는 뒤 행이 이긴다. 기존 마스터를 모두 지운 뒤 다시 넣는 전체 교체라 실패하면 롤백된다. 응답 loaded/skipped/total. 감사기록 DRUG_MASTER_UPLOAD. SYSTEM_ADMIN 토큰 필요.","operationId":"upload_1","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"심평원 약제급여목록표 엑셀 파일 (xls/xlsx)"}},"required":["file"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseUploadResult"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/update":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 수정","description":"코드명·설명·부가값·정렬·사용여부를 바꾼다. 코드값은 바꿀 수 없다. 사용여부를 N 으로 두면 검색 선택 목록에서만 사라지고, 이미 그 값으로 저장된 데이터는 이름 그대로 보인다. 감사기록 CODE_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateCode","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeItemUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"codeId":"(수정할 코드 PK)","codeName":"(선택 — 코드명)","codeDesc":"(선택 — 설명)","extraValue":"(선택 — 부가값)","sortNo":"(선택 — 정렬 순번)","useYn":"(선택 — 사용 여부 (Y/N))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"codeId":3,"codeName":"접수대기","codeDesc":"약국 확인 전","extraValue":"blue","sortNo":10,"useYn":"Y"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCodeItemView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/groups/update":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 그룹 수정","description":"그룹명·설명·정렬·사용여부를 바꾼다. 보낸 항목만 바뀌고 groupCode 는 바꿀 수 없다. 감사기록 CODE_GROUP_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeGroupUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"groupCode":"(수정할 그룹코드)","groupName":"(선택 — 그룹명)","groupDesc":"(선택 — 설명)","sortNo":"(선택 — 정렬 순번)","useYn":"(선택 — 사용 여부 (Y/N))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"groupCode":"carrier","groupName":"택배사","groupDesc":"송장 등록 시 선택","sortNo":30,"useYn":"Y"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCodeGroupView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/groups/delete":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 그룹 삭제","description":"빈 그룹만 지울 수 있다. 시스템 그룹(systemYn=Y)이거나 코드가 남아 있으면 COMMON_001. 감사기록 CODE_GROUP_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deleteGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeGroupDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"groupCode":"(삭제할 그룹코드)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"groupCode":"carrier"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/groups/create":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 그룹 등록","description":"새 코드 그룹을 만든다. groupCode 는 영문·숫자·밑줄만 쓰고 중복이면 COMMON_001. 감사기록 CODE_GROUP_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeGroupCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"groupCode":"(그룹코드 — 영문 소문자·숫자·밑줄만)","groupName":"(그룹명)","groupDesc":"(선택 — 설명)","sortNo":"(선택 — 정렬 순번)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"groupCode":"carrier","groupName":"택배사","groupDesc":"송장 등록 시 선택하는 택배사","sortNo":30}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCodeGroupView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/delete":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 삭제","description":"시스템 그룹의 코드는 지울 수 없다(사용여부 N 을 쓴다). 그 외 그룹의 코드만 삭제. 감사기록 CODE_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deleteCode","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeItemDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"codeId":"(삭제할 코드 PK)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"codeId":42}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/create":{"post":{"tags":["관리자 / 코드관리"],"summary":"코드 등록","description":"그룹에 코드를 추가한다. 같은 그룹에 같은 codeValue 가 있으면 COMMON_001. 새 코드값은 백엔드가 알지 못하므로, 화면 표시용 목록을 늘릴 때만 쓴다. 감사기록 CODE_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createCode","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeItemCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"groupCode":"(소속 그룹코드)","codeValue":"(코드값 — 같은 그룹 안에서 중복 불가)","codeName":"(코드명)","codeDesc":"(선택 — 설명)","extraValue":"(선택 — 부가값 (태그 색상 등))","sortNo":"(선택 — 정렬 순번)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"groupCode":"carrier","codeValue":"cu","codeName":"CU편의점택배","codeDesc":"편의점 접수 택배","extraValue":"green","sortNo":60}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCodeItemView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/{board}-categories/create":{"post":{"tags":["관리자 / 게시판"],"summary":"카테고리 작성","description":"관리자웹 카테고리 메뉴의 등록 모달. 경로의 board 는 faq 또는 qna, 본문 name 필수, sort 는 정렬 순서(기본 0). 활성 상태로 만들어진다. 감사기록 BBS_CATEGORY_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createCategory","parameters":[{"name":"board","in":"path","description":"게시판 종류: faq | qna","required":true,"schema":{"type":"string"},"example":"faq"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCategoryCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"name":"(카테고리명)","sort":"(선택 — 정렬 순서 (오름차순) — null = 기본값)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"name":"배송/결제","sort":1}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCategoryView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/qnas/answer":{"post":{"tags":["관리자 / 게시판"],"summary":"QnA 답변 작성/수정","description":"관리자웹 QnA 답변 메뉴의 답변 저장 버튼. 대상은 본문 postId, answer 필수. 답변을 저장하고 상태를 답변완료(ANSWERED)로 바꾸며 답변 시각을 기록한다. 질문한 회원에게 FCM 푸시(문의 답변 도착, relatedType=qna)를 보낸다(이미 답변된 글을 수정해도 다시 발송). 변경 전/후 값으로 감사기록 BBS_QNA_ANSWER. SYSTEM_ADMIN 토큰 필요.","operationId":"answerQna","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminQnaAnswerRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"postId":"(답변 대상 문의글 PK — GET /api/v1/admin/bbs/qnas 목록의 id)","answer":"(답변 내용)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"postId":42,"answer":"결제 완료 후 보통 1~2일 내 도착합니다."}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseQnaView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/notices":{"post":{"tags":["관리자 / 게시판"],"summary":"공지 작성","description":"관리자웹 공지 관리 메뉴의 등록 모달. subject, contents 필수, categoryId 는 선택(없는 카테고리면 COMMON_001). 저장 즉시 전체 회원에게 FCM 푸시(새 공지가 등록되었습니다, relatedType=notice)가 broadcast 되므로 임시 저장 용도로 쓰면 안 된다. 감사기록 BBS_NOTICE_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createNotice","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"subject":"(제목)","contents":"(본문 (HTML/텍스트))","categoryId":"(선택 — 카테고리 PK — GET /api/v1/admin/bbs/faq-categories 의 id, FAQ 는 필수 / 공지는 null)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"subject":"추석 연휴 배송 안내","contents":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다.","categoryId":2}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/notices/update":{"post":{"tags":["관리자 / 게시판"],"summary":"공지 수정","description":"관리자웹 공지 관리 메뉴의 수정 모달. 대상은 본문 postId(공지가 아니거나 삭제된 글은 COMMON_003). subject/contents/categoryId 중 보낸 항목만 바꾸고 null 은 유지. 푸시는 다시 나가지 않는다. 감사기록 BBS_NOTICE_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateNotice","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"postId":"(수정 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id)","subject":"(선택 — 제목 — null = 미변경)","contents":"(선택 — 본문 — null = 미변경)","categoryId":"(선택 — 카테고리 PK (FAQ) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"postId":15,"subject":"추석 연휴 배송 안내","contents":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다.","categoryId":2}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/notices/delete":{"post":{"tags":["관리자 / 게시판"],"summary":"공지 삭제","description":"관리자웹 공지 관리 메뉴의 삭제 버튼. 대상은 본문 postId. soft delete 라 앱 목록·상세에서 즉시 사라지지만 DB 행은 남는다. 감사기록 BBS_NOTICE_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deleteNotice","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"postId":"(삭제 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"postId":15}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/faqs":{"post":{"tags":["관리자 / 게시판"],"summary":"FAQ 작성","description":"관리자웹 FAQ 관리 메뉴의 등록 모달. subject(질문), contents(답변) 필수, categoryId 는 앱 탭 분류용이며 없는 카테고리면 COMMON_001. 공지와 달리 푸시는 나가지 않는다. 감사기록 BBS_FAQ_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"createFaq","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostCreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"subject":"(제목)","contents":"(본문 (HTML/텍스트))","categoryId":"(선택 — 카테고리 PK — GET /api/v1/admin/bbs/faq-categories 의 id, FAQ 는 필수 / 공지는 null)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"subject":"추석 연휴 배송 안내","contents":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다.","categoryId":2}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/faqs/update":{"post":{"tags":["관리자 / 게시판"],"summary":"FAQ 수정","description":"관리자웹 FAQ 관리 메뉴의 수정 모달. 대상은 본문 postId(FAQ 가 아니거나 삭제된 글은 COMMON_003). 보낸 항목만 바꾸고 null 은 유지. 감사기록 BBS_FAQ_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateFaq","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"postId":"(수정 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id)","subject":"(선택 — 제목 — null = 미변경)","contents":"(선택 — 본문 — null = 미변경)","categoryId":"(선택 — 카테고리 PK (FAQ) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"postId":15,"subject":"추석 연휴 배송 안내","contents":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다.","categoryId":2}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/faqs/delete":{"post":{"tags":["관리자 / 게시판"],"summary":"FAQ 삭제","description":"관리자웹 FAQ 관리 메뉴의 삭제 버튼. 대상은 본문 postId. soft delete. 감사기록 BBS_FAQ_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deleteFaq","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPostDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"postId":"(삭제 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"postId":15}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/categories/update":{"post":{"tags":["관리자 / 게시판"],"summary":"카테고리 수정","description":"관리자웹 카테고리 메뉴의 수정 모달. 대상은 본문 categoryId(없으면 COMMON_003). name / sort / active 중 보낸 항목만 바꾸고 null 은 유지. 게시판 종류는 바꿀 수 없다. 감사기록 BBS_CATEGORY_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"updateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCategoryUpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"categoryId":"(수정 대상 카테고리 PK — GET /api/v1/admin/bbs/{board}-categories 의 id)","name":"(선택 — 카테고리명 — null = 미변경)","sort":"(선택 — 정렬 순서 — null = 미변경)","active":"(선택 — 활성 여부 (false 면 목록에서 숨김) — null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"categoryId":2,"name":"배송/결제","sort":1,"active":true}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseCategoryView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/categories/delete":{"post":{"tags":["관리자 / 게시판"],"summary":"카테고리 비활성화 (삭제)","description":"관리자웹 카테고리 메뉴의 삭제 버튼. 대상은 본문 categoryId. 행을 지우지 않고 active=false 로 바꿔 앱 목록에서만 숨기며, 그 카테고리를 쓰던 글은 그대로 남는다. 감사기록 BBS_CATEGORY_DELETE. SYSTEM_ADMIN 토큰 필요.","operationId":"deactivateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCategoryDeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"categoryId":"(삭제 대상 카테고리 PK — GET /api/v1/admin/bbs/{board}-categories 의 id)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"categoryId":2}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/auth/reset-password":{"post":{"tags":["관리자 / 인증"],"summary":"관리자 비밀번호 찾기 (임시 비밀번호 메일)","description":"관리자웹 로그인 화면의 비밀번호 찾기 모달에서 호출한다. adminId 와 등록 이메일(adminEmail)이 일치하면 12자 임시 비밀번호로 바꾸고 그 이메일로 발송한다. 불일치는 AUTH_002, 탈퇴 계정은 MEMBER_004, 메일 발송 실패 시 비밀번호 변경도 롤백되고 COMMON_004. 로그인 불필요.","operationId":"resetPassword_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResetPasswordRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(관리자 로그인 아이디)","adminEmail":"(계정에 등록된 이메일 — 아이디와 일치해야 임시 비밀번호 발송)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":"pharmacist01","adminEmail":"pharm01@yaknaru.local"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/admin/auth/refresh":{"post":{"tags":["관리자 / 인증"],"summary":"관리자 토큰 갱신","description":"관리자웹 요청 계층이 access 토큰 만료(401)를 받으면 자동으로 호출한다. 관리자용(userType=ADMIN) refresh 토큰만 받으며 회원 토큰이나 위조·만료 토큰은 AUTH_004. 새 access/refresh 토큰 쌍과 adminInfo 를 다시 돌려준다. 로그인 불필요(본문 refreshToken 만 사용).","operationId":"refresh_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminRefreshRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"refreshToken":"(갱신 토큰 — POST /api/v1/admin/auth/login 응답의 refreshToken)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"refreshToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwaGFybWFjaXN0MDEiLCJ0eXAiOiJyZWZyZXNoIn0.9qZk…"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminTokenResponse"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/admin/auth/login":{"post":{"tags":["관리자 / 인증"],"summary":"관리자 로그인","description":"관리자웹 로그인 화면에서 호출한다. adminId + adminPass 검증 후 access 토큰(30분)/refresh 토큰(14일)과 adminInfo(역할 포함)를 돌려주고 마지막 로그인 시각을 갱신한다. 계정 상태에 따라 거절된다: 가입 검토 대기(PENDING)와 정지(SUSPENDED)는 AUTH_005, 탈퇴(WITHDRAWN)는 MEMBER_004, 아이디·비밀번호 불일치는 AUTH_002. 로그인 불필요.","operationId":"login_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLoginRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(관리자 로그인 아이디 — 약사 회원가입(POST /api/v1/pharmacist/signup) 또는 SYSTEM_ADMIN 등록 시 지정)","adminPass":"(비밀번호 (평문, TLS 구간 전송))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":"pharmacist01","adminPass":"********"}}},"example":null}},"required":true},"responses":{"200":{"description":"로그인 성공","content":{"application/json":{"examples":{"약사 계정":{"description":"약사 계정","value":{"success":true,"data":{"tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIzMSIsInVzZXJUeXBlIjoiQURNSU4ifQ.xxxxx","refreshToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIzMSIsInR5cCI6InJlZnJlc2gifQ.yyyyy","expiresIn":1800,"adminInfo":{"id":31,"adminId":"pharm_kim","adminName":"김약사","adminEmail":"kim@pharmacy.kr","adminTel":"010-1111-2222","adminState":"ACTIVE","roles":["PHARMACY_ADMIN"]}}}}}}}},"401":{"description":"아이디 또는 비밀번호 불일치","content":{"application/json":{"examples":{"AUTH_002":{"description":"AUTH_002","value":{"success":false,"error":{"code":"AUTH_002","message":"아이디 또는 비밀번호가 일치하지 않습니다."}}}}}}},"403":{"description":"가입 검토 대기 또는 정지된 계정","content":{"application/json":{"examples":{"PENDING":{"description":"PENDING","value":{"success":false,"error":{"code":"AUTH_005","message":"회원가입 검토 대기 중입니다. 운영자 승인 후 로그인할 수 있습니다."}}},"SUSPENDED":{"description":"SUSPENDED","value":{"success":false,"error":{"code":"AUTH_005","message":"정지된 계정입니다."}}}}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/admin/admin-users/update":{"post":{"tags":["관리자 / 관리자 계정"],"summary":"관리자 계정 수정","description":"관리자웹 관리자 계정 메뉴의 수정 모달에서 호출한다. 대상은 본문 adminId(PK). 이름·이메일·전화·역할(roles)·상태(adminState: ACTIVE/SUSPENDED/WITHDRAWN)를 부분 수정하며 null 은 유지. 본인 계정의 역할·상태 변경은 락아웃 방지를 위해 COMMON_001 로 거절된다. 변경 전/후 값으로 감사기록 ADMIN_USER_UPDATE. SYSTEM_ADMIN 토큰 필요.","operationId":"update_4","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"platform":"(대상 플랫폼 — android / ios)","up_bool":"(선택 — 강제 업데이트 사용 여부 — yes / no, null = 미변경)","up_build":"(선택 — 강제 업데이트 기준 빌드 번호 — null = 미변경)","up_img":"(선택 — 업데이트 안내 이미지 URL — null = 미변경)","up_img_width":"(선택 — 업데이트 안내 이미지 가로 (px) — null = 미변경)","up_img_height":"(선택 — 업데이트 안내 이미지 세로 (px) — null = 미변경)","agree_bool":"(선택 — 약관 재동의 강제 여부 — yes / no, null = 미변경)","agree_no":"(선택 — 재동의가 필요한 약관 버전 번호 — null = 미변경)","popup_bool":"(선택 — 팝업 노출 여부 — yes / no, null = 미변경)","popup_img":"(선택 — 팝업 이미지 URL — null = 미변경)","server_bool":"(선택 — 서버 점검 중 여부 — yes / no, null = 미변경)","server_img":"(선택 — 점검 안내 이미지 URL — null = 미변경)","server_img_width":"(선택 — 점검 안내 이미지 가로 (px) — null = 미변경)","server_img_height":"(선택 — 점검 안내 이미지 세로 (px) — null = 미변경)","ocr_bool":"(선택 — 처방전 OCR 사용 여부 — yes / no, null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"platform":"android","up_bool":"no","up_build":12,"up_img":"https://cdn.yaknaru.co.kr/app/update.png","up_img_width":720,"up_img_height":1280,"agree_bool":"no","agree_no":2,"popup_bool":"no","popup_img":"https://cdn.yaknaru.co.kr/app/popup.png","server_bool":"no","server_img":"https://cdn.yaknaru.co.kr/app/maint.png","server_img_width":720,"server_img_height":1280,"ocr_bool":"no"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/reset-password":{"post":{"tags":["관리자 / 관리자 계정"],"summary":"관리자 비밀번호 강제 변경","description":"관리자웹 관리자 계정 메뉴에서 운영자가 다른 계정의 비밀번호를 바로 바꿀 때 호출한다. 대상은 본문 adminId, 현재 비밀번호 검증 없이 newPassword(6~64자)로 교체한다. 감사기록 ADMIN_USER_PASSWORD_RESET 을 남기되 비밀번호 값은 기록하지 않는다. SYSTEM_ADMIN 토큰 필요.","operationId":"resetPassword_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordByAdminRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id)","newPassword":"(새 비밀번호 (6~64자))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":3,"newPassword":"********"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/pharmacies/remove":{"post":{"tags":["관리자 / 관리자 계정"],"summary":"약사-약국 매핑 해제","description":"관리자웹 관리자 계정 상세에서 약국 연결을 끊을 때 호출한다. 본문 adminId(관리자 PK) + pharmacyId(약국 PK, 코드 아님). 응답은 갱신된 매핑 목록 전체. 매핑이 모두 없어진 약사는 처방전·주문 메뉴에서 아무 것도 보지 못한다. 감사기록 ADMIN_USER_PHARMACY_REMOVE. SYSTEM_ADMIN 토큰 필요.","operationId":"removeMapping","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PharmacyMappingRemoveRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id)","pharmacyId":"(해제할 약국 PK — 관리자 상세(/detail) pharmacies 항목의 pharmacyId)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":3,"pharmacyId":1}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListPharmacyMappingItem"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/pharmacies/add":{"post":{"tags":["관리자 / 관리자 계정"],"summary":"약사-약국 매핑 추가","description":"관리자웹 관리자 계정 상세에서 약국을 연결할 때 호출한다. 본문 adminId(관리자 PK) + pharmacyCode. 이미 매핑돼 있으면 그대로 두고, 없는 약국 코드는 COMMON_003. 응답은 갱신된 매핑 목록 전체. 감사기록 ADMIN_USER_PHARMACY_ADD. SYSTEM_ADMIN 토큰 필요.","operationId":"addMapping","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PharmacyMappingRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id)","pharmacyCode":"(매핑할 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식))"}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":3,"pharmacyCode":"PH-001"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListPharmacyMappingItem"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/create":{"post":{"tags":["관리자 / 관리자 계정"],"summary":"관리자 계정 생성","description":"관리자웹 관리자 계정 메뉴의 신규 등록 모달에서 호출한다. roles 에 SYSTEM_ADMIN 이 있으면 운영자, 아니면 약사 계정으로 만들며 상태는 즉시 ACTIVE. PHARMACY_ADMIN 은 pharmacyCodes 로 초기 약국 매핑을 함께 걸 수 있다(없는 코드는 COMMON_003). 아이디 중복은 COMMON_001. 감사기록 ADMIN_USER_CREATE. SYSTEM_ADMIN 토큰 필요.","operationId":"create_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(관리자 로그인 아이디 (3~64자, 중복 불가))","password":"(초기 비밀번호 (6~64자))","adminName":"(관리자 이름 (40자 이하))","adminEmail":"(선택 — 관리자 이메일 (120자 이하))","adminTel":"(선택 — 전화번호 (20자 이하))","roles":["(권한 집합 (1개 이상) — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자)"],"pharmacyCodes":["(선택 — 등록 시 초기 매핑할 약국 코드 목록 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식), PHARMACY_ADMIN 일 때만 의미)"]}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":"pharmacist06","password":"********","adminName":"홍길동","adminEmail":"pharm06@yaknaru.local","adminTel":"010-1234-5678","roles":["PHARMACY_ADMIN"],"pharmacyCodes":["PH-001"]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/addresses/update":{"post":{"tags":["배송지(앱)"],"summary":"배송지 수정","description":"앱 배송지 수정 화면(AddressEdit)에서 호출한다. 대상은 본문 addressId 로 식별하며 본인 배송지가 아니면 COMMON_003. null 로 보낸 필드는 변경하지 않는다. isDefault=true 면 기본 배송지로 승격하고 다른 배송지의 기본 표시를 해제한다(기본 해제는 불가). 회원 토큰 필요.","operationId":"update_5","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"platform":"(대상 플랫폼 — android / ios)","up_bool":"(선택 — 강제 업데이트 사용 여부 — yes / no, null = 미변경)","up_build":"(선택 — 강제 업데이트 기준 빌드 번호 — null = 미변경)","up_img":"(선택 — 업데이트 안내 이미지 URL — null = 미변경)","up_img_width":"(선택 — 업데이트 안내 이미지 가로 (px) — null = 미변경)","up_img_height":"(선택 — 업데이트 안내 이미지 세로 (px) — null = 미변경)","agree_bool":"(선택 — 약관 재동의 강제 여부 — yes / no, null = 미변경)","agree_no":"(선택 — 재동의가 필요한 약관 버전 번호 — null = 미변경)","popup_bool":"(선택 — 팝업 노출 여부 — yes / no, null = 미변경)","popup_img":"(선택 — 팝업 이미지 URL — null = 미변경)","server_bool":"(선택 — 서버 점검 중 여부 — yes / no, null = 미변경)","server_img":"(선택 — 점검 안내 이미지 URL — null = 미변경)","server_img_width":"(선택 — 점검 안내 이미지 가로 (px) — null = 미변경)","server_img_height":"(선택 — 점검 안내 이미지 세로 (px) — null = 미변경)","ocr_bool":"(선택 — 처방전 OCR 사용 여부 — yes / no, null = 미변경)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"platform":"android","up_bool":"no","up_build":12,"up_img":"https://cdn.yaknaru.co.kr/app/update.png","up_img_width":720,"up_img_height":1280,"agree_bool":"no","agree_no":2,"popup_bool":"no","popup_img":"https://cdn.yaknaru.co.kr/app/popup.png","server_bool":"no","server_img":"https://cdn.yaknaru.co.kr/app/maint.png","server_img_width":720,"server_img_height":1280,"ocr_bool":"no"}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAddressView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/addresses/delete":{"post":{"tags":["배송지(앱)"],"summary":"배송지 삭제","description":"앱 배송지 관리 화면(AddressManagement)에서 호출한다. 대상은 본문 addressId. 실제 삭제가 아닌 soft delete 이며, 삭제한 배송지가 기본 배송지였다면 남은 배송지 중 첫 번째가 자동으로 기본 배송지가 된다. 회원 토큰 필요.","operationId":"delete_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"addressId":"(삭제 대상 배송지 PK — GET /api/v1/addresses 의 deliveryAddressSeq)"}},"sample":{"summary":"✅ 실제 값 예시","value":{"addressId":12}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseVoid"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/addresses/create":{"post":{"tags":["배송지(앱)"],"summary":"배송지 추가","description":"앱 배송지 등록 화면(AddressEdit)에서 호출한다. 받는 분 이름과 연락처는 필수. 회원의 첫 배송지이거나 isDefault=true 로 보내면 기본 배송지가 되고, 기존 기본 배송지는 자동 해제된다. 회원 토큰 필요.","operationId":"create_3","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"},"examples":{"describe":{"summary":"📖 각 필드에 넣을 값 (설명)","value":{"adminId":"(관리자 로그인 아이디 (3~64자, 중복 불가))","password":"(초기 비밀번호 (6~64자))","adminName":"(관리자 이름 (40자 이하))","adminEmail":"(선택 — 관리자 이메일 (120자 이하))","adminTel":"(선택 — 전화번호 (20자 이하))","roles":["(권한 집합 (1개 이상) — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자)"],"pharmacyCodes":["(선택 — 등록 시 초기 매핑할 약국 코드 목록 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식), PHARMACY_ADMIN 일 때만 의미)"]}},"sample":{"summary":"✅ 실제 값 예시","value":{"adminId":"pharmacist06","password":"********","adminName":"홍길동","adminEmail":"pharm06@yaknaru.local","adminTel":"010-1234-5678","roles":["PHARMACY_ADMIN"],"pharmacyCodes":["PH-001"]}}},"example":null}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAddressView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/shop/settings":{"get":{"tags":["건강샵(앱)"],"summary":"배송비 정책 조회","description":"앱 장바구니·결제 화면에서 배송비 계산에 쓴다. deliveryFee(기본 배송비)와 freeThreshold(무료배송 기준 금액)를 돌려준다. 회원 토큰 필요.","operationId":"getSettings","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseSettingView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/shop/products":{"get":{"tags":["건강샵(앱)"],"summary":"상품 목록","description":"앱 건강샵 탭 진입 시 호출한다. 관리자가 노출(visible=true)로 둔 삭제되지 않은 상품만 등록순으로 돌려준다. id 는 상품 코드(HP-001 형식)이며 주문 시 productId 로 쓴다. 회원 토큰 필요.","operationId":"getProducts","responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"상품 1건":{"description":"상품 1건","value":{"success":true,"data":[{"id":"HP-001","category":"비타민","emoji":"🍊","name":"비타민C 1000","brand":"약나루헬스","brief":"하루 한 알 고함량 비타민C","price":15900,"originalPrice":19900,"badge":"BEST","visible":true,"functionality":"항산화 및 면역 기능 유지에 도움","intake":"1일 1회, 1회 1정을 물과 함께 섭취","caution":"특정 질환이 있는 경우 전문가와 상담","image":"/uploads/shop/hp-001.jpg","detailImages":["/uploads/shop/hp-001-d1.jpg"]}]}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListProductView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/shop/orders":{"get":{"tags":["건강샵(앱)"],"summary":"내 건강샵 주문 목록","description":"앱 건강샵 주문 내역에서 호출한다. 본인 주문을 최신순으로 돌려주며 status 는 PAID/SHIPPING/DELIVERED, statusLabel 은 한글 라벨. 회원 토큰 필요.","operationId":"getMyOrders","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListOrderView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/messages":{"get":{"tags":["푸시(앱)"],"summary":"내 알림함","description":"앱 알림 목록 화면(PushList)에서 호출한다. 본인에게 보낸 메시지와 전체 공지(broadcast, memberId 없음)를 최신순으로 페이징한다. readAt 이 없으면 미읽음. relatedType(prescription_approved / prescription_rejected / order / delivery / eligibility / notice / qna)과 relatedId, payload(JSON 문자열)로 화면 이동에 쓴다. 회원 토큰 필요.","operationId":"inbox","parameters":[{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"조회 성공 (Spring Data Page 형태)","content":{"application/json":{"examples":{"개인 알림 1건 + 전체 공지 1건":{"description":"개인 알림 1건 + 전체 공지 1건","value":{"success":true,"data":{"content":[{"id":88,"memberId":12,"title":"배송이 시작되었습니다","body":"약이 배송 출발했습니다. 배송 조회로 위치를 확인하세요.","payload":"{\"pharmacyName\":\"약나루약국\",\"pharmacyCode\":\"PH-001\",\"deliveryNumber\":\"123456789012\",\"deliveryCompany\":\"CJ대한통운\"}","relatedType":"delivery","relatedId":41,"createdAt":"2026-09-11T08:30:01.204"},{"id":80,"title":"새 공지가 등록되었습니다","body":"추석 연휴 배송 안내","relatedType":"notice","relatedId":7,"readAt":"2026-09-09T12:00:10.5","createdAt":"2026-09-09T11:00:00.1"}],"pageable":{"pageNumber":0,"pageSize":20,"sort":{"empty":false,"sorted":true,"unsorted":false},"offset":0,"paged":true,"unpaged":false},"last":true,"totalElements":2,"totalPages":1,"size":20,"number":0,"sort":{"empty":false,"sorted":true,"unsorted":false},"first":true,"numberOfElements":2,"empty":false}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageMessageInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/push/messages/unread-count":{"get":{"tags":["푸시(앱)"],"summary":"미읽음 알림 개수","description":"앱 홈(Home) 화면의 알림 뱃지용. 본인 메시지와 전체 공지 중 readAt 이 없는 건수를 {count} 로 돌려준다. 회원 토큰 필요.","operationId":"unreadCount","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringLong"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/prescriptions/detail":{"get":{"tags":["처방전·주문(앱)"],"summary":"내 처방전 상세","description":"식별자는 쿼리 id(처방전 id). 본인 처방전이 아니면 AUTH_005, 없으면 COMMON_003. 단계별 진입 시각(readyAt/paidAt 등)과 약품 목록, 인식 정보(partnerInfo)를 포함한다. 앱 주문 화면은 주로 /api/v1/orders/detail 을 쓰고, 이 API 는 처방전 원본 관점(이미지 URL, 약사 메모 등)이 필요할 때 쓴다. 회원 토큰 필요.","operationId":"detail","parameters":[{"name":"id","in":"query","description":"처방전 id","required":true,"schema":{"type":"integer","format":"int64"},"example":41}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/pharmacist/check-id":{"get":{"tags":["약사 회원가입"],"summary":"약사 아이디 중복 확인","description":"관리자웹 회원가입 화면(signup)의 중복확인 버튼. 관리자 계정 전체(약사·운영자)를 대상으로 검사해 {adminId, available} 를 돌려준다. 빈 값이면 available=false. 로그인 불필요.","operationId":"checkId_1","parameters":[{"name":"adminId","in":"query","description":"확인할 관리자 로그인 아이디","required":true,"schema":{"type":"string"},"example":"pharm_kim"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringObject"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/pharmacies":{"get":{"tags":["약국(앱)"],"summary":"약국 검색","description":"앱 약국 찾기 화면에서 호출한다. gpsX(경도)와 gpsY(위도)를 함께 주면 거리순으로 정렬되고 각 항목의 distance(미터)가 채워지며, 없으면 이름순. keyword 는 약국명 검색, deliveryYn=Y 면 배송 가능 약국만. effectiveStatus 는 요일별 영업시간과 현재 시각(KST)으로 계산한 실효 상태(영업중/준비중)이며 화면 표시는 이 값을 쓴다. 로그인 불필요.","operationId":"search","parameters":[{"name":"gpsX","in":"query","description":"현재 위치 경도(longitude). gpsY 와 함께 줘야 거리순 정렬","required":false,"schema":{"type":"number"},"example":127.0276},{"name":"gpsY","in":"query","description":"현재 위치 위도(latitude)","required":false,"schema":{"type":"number"},"example":37.4979},{"name":"keyword","in":"query","description":"약국명 검색어(부분 일치)","required":false,"schema":{"type":"string"},"example":"약나루"},{"name":"deliveryYn","in":"query","description":"배송 가능 약국만 조회하려면 Y","required":false,"schema":{"type":"string"},"example":"Y"},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"검색 성공 (Spring Data Page 형태)","content":{"application/json":{"examples":{"위치 기반 검색 1건":{"description":"위치 기반 검색 1건","value":{"success":true,"data":{"content":[{"pharmacyCode":"PH-001","pharmacyName":"약나루약국","pharmacyPhone":"02-1234-5678","zipcode":"06236","pharmacyAddress":"서울특별시 강남구 테헤란로 123","pharmacyDetailAddress":"1층","gpsLat":37.4979,"gpsLon":127.0276,"effectiveStatus":"영업중","deliveryYn":"Y","alarmPhone":"010-1111-2222","pharmacistName":"김약사","pharmacistPhone":"010-1111-2222","licenseNum":"12345","businessNum":"123-45-67890","accountBankName":"국민은행","accountBankNumber":"123456-78-901234","accountOwner":"김약사","openTimeMon":"09:00~18:00","openTimeTue":"09:00~18:00","openTimeWed":"09:00~18:00","openTimeThu":"09:00~18:00","openTimeFri":"09:00~18:00","openTimeSat":"09:00~13:00","openTimeSun":"휴무","pharmacyCharge":5.0,"pendingAdminCount":0,"distance":842}],"pageable":{"pageNumber":0,"pageSize":20,"sort":{"empty":true,"sorted":false,"unsorted":true},"offset":0,"paged":true,"unpaged":false},"last":true,"totalElements":1,"totalPages":1,"size":20,"number":0,"sort":{"empty":true,"sorted":false,"unsorted":true},"first":true,"numberOfElements":1,"empty":false}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePagePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/pharmacies/detail":{"get":{"tags":["약국(앱)"],"summary":"약국 상세","description":"앱 약국 상세/선택 화면에서 호출한다. 식별자는 쿼리 code(약국 코드, 예 PH-001). 없는 코드는 COMMON_003. distance 는 채워지지 않는다. 로그인 불필요.","operationId":"getOne","parameters":[{"name":"code","in":"query","description":"약국 코드","required":true,"schema":{"type":"string"},"example":"PH-001"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/orders":{"get":{"tags":["처방전·주문(앱)"],"summary":"내 주문 내역","description":"앱 홈(Home)의 최근 주문과 주문 내역 화면(OrderHistory)에서 호출한다. 본인 처방전을 최신순으로 페이징한 뒤 접수일(targetDate, yyyy-MM-dd) 별로 묶어 RN SectionList 형태로 돌려준다. 목록의 medicineList 는 항상 빈 배열이며 약품 목록은 상세에서만 제공된다. 회원 토큰 필요.","operationId":"history","parameters":[{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기(처방전 건수 기준, 날짜 그룹 수 아님)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"날짜 그룹 2개":{"description":"날짜 그룹 2개","value":{"success":true,"data":[{"targetDate":"2026-09-10","deliveryList":[{"prescriptionSeq":41,"prescriptionStatus":"06","prescriptionStatusName":"배송중","prescriptionRegdate":"2026-09-10","prescriptionPrice":12500,"totalPrice":15500,"receiveType":"onLine","pharmacyCode":"PH-001","pharmacyName":"약나루약국","medicineList":[]}]},{"targetDate":"2026-09-03","deliveryList":[{"prescriptionSeq":37,"prescriptionStatus":"03","prescriptionStatusName":"조제불가","prescriptionRegdate":"2026-09-03","unavailableReason":"재고 없음","receiveType":"offLine","pharmacyCode":"PH-002","pharmacyName":"건강약국","medicineList":[]}]}]}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListOrderHistoryGroup"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/orders/detail":{"get":{"tags":["처방전·주문(앱)"],"summary":"주문 상세","description":"앱 주문 진행 화면(MedicineOrder)과 주문 상세 화면(MedicineOrderDetail)에서 호출한다. 식별자는 쿼리 id(처방전 id). 본인 처방전이 아니면 AUTH_005, 없으면 COMMON_003. 처방전 인식 정보(partnerInfo)가 연결된 경우 약품 목록(medicineList)과 병원·의사 정보가 함께 오고, 03 조제불가 건은 pharmacyCode 로 거절 약국을 식별해 다른 약국 선택 흐름에 쓴다. 회원 토큰 필요.","operationId":"detail_1","parameters":[{"name":"id","in":"query","description":"처방전(주문) id","required":true,"schema":{"type":"integer","format":"int64"},"example":41}],"responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"택배 배송중 주문":{"description":"택배 배송중 주문","value":{"success":true,"data":{"prescriptionSeq":41,"prescriptionStatus":"06","prescriptionStatusName":"배송중","reqDate":"2026-09-10T09:12:33.481","receiveType":"onLine","prescriptionPrice":12500,"deliveryPrice":3000,"totalPrice":15500,"medicineDirection":"1일 3회 식후 30분 복용","medicineList":[{"drgCd":"641102470","drgNm":"타이레놀정500밀리그램","dosage":"1","daysTotal":"3"}],"pharmacyCode":"PH-001","pharmacyName":"약나루약국","pharmacyPhone":"02-1234-5678","pharmacyAddress":"서울특별시 강남구 테헤란로 123 1층","deliveryName":"홍길동","deliveryPhone":"010-1234-5678","deliveryAddress":"서울특별시 서초구 반포대로 45","deliveryDetailAddress":"101동 202호","deliveryNumber":"123456789012","deliveryCompany":"CJ대한통운","partnerInfo":{"seq":15,"hospitalName":"서울내과의원","doctorName":"이의사","patientName":"홍길동","prescriptionDate":"2026-09-10","useDays":"3"}}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseOrderDetail"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/members/me":{"get":{"tags":["회원(앱)"],"summary":"내 정보 조회","description":"앱 더보기(More)·내 정보 수정(EditProfile) 화면에서 호출한다. 로그인 응답의 myInfo 와 같은 형태. 회원 토큰 필요.","operationId":"me","responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"활성 회원":{"description":"활성 회원","value":{"success":true,"data":{"id":12,"memId":"hong123","memEmail":"hong@example.com","memName":"홍길동","memBirth":"1990-01-15","memGender":"1","memTel":"010-1234-5678","memPush":"Y","memState":"ACTIVE","roles":["USER"]}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMemberInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/eligibility/latest":{"get":{"tags":["자격 심사(앱)"],"summary":"내 자격 최신 1건 조회","description":"앱 약 배송 자격 화면(DeliveryEligibility)과 배송지 관리 화면(AddressManagement)의 택배 가능 여부 판단에서 호출한다. 본인 신청 중 가장 최근 1건을 첨부 문서 목록과 함께 돌려주며, 신청 이력이 없으면 data 가 없다(null). state: I 심사중 / S 승인 / R 반려(rejectDesc 에 사유). 회원 토큰 필요.","operationId":"latest","responses":{"200":{"description":"조회 성공 (이력 없으면 data 생략)","content":{"application/json":{"examples":{"심사중":{"description":"심사중","value":{"success":true,"data":{"summary":{"id":9,"memberId":12,"state":"I","documentTypes":"ltc65plus","documentCount":1,"createdAt":"2026-09-11T10:15:30.123","updatedAt":"2026-09-11T10:15:30.123"},"documents":[{"id":21,"fileName":"인정서.jpg","fileSize":184233,"mimeType":"image/jpeg","fileUrl":"/uploads/eligibility/9/2026-09-11/8c1d2e__인정서.jpg"}]}}},"신청 이력 없음":{"description":"신청 이력 없음","value":{"success":true}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilityDetail"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/codes":{"get":{"tags":["공통코드"],"summary":"그룹별 코드 목록","description":"groupCode 의 사용중 코드를 정렬 순서대로 준다. 앱은 주문 상태 표시(prescription_status)에 쓰며, codeName 은 화면에 보일 이름, codeDesc 는 상태 안내 문장, extraValue 는 표시 색이다. 없는 그룹이면 COMMON_003. 회원 토큰 필요.","operationId":"listCodes","parameters":[{"name":"groupCode","in":"query","description":"groupCode = 코드 그룹","required":true,"schema":{"type":"string"},"example":"prescription_status"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCodeItemView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/bbs/qna-form":{"get":{"tags":["게시판(앱)"],"summary":"Q&A 작성 폼 (카테고리 목록)","description":"앱 문의 작성 화면(QnaWrite)에 들어갈 때 호출한다. 활성 Q&A 카테고리를 정렬순으로 돌려준다. 회원 토큰 필요.","operationId":"qnaForm","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCategoryView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/bbs/notices":{"get":{"tags":["게시판(앱)"],"summary":"공지사항 목록","description":"앱 공지사항 목록 화면(NoticeList)에서 호출한다. 삭제되지 않은 공지를 페이징해 돌려주며 contents(본문)도 포함된다. 로그인 불필요.","operationId":"notices","parameters":[{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"조회 성공 (Spring Data Page 형태)","content":{"application/json":{"examples":{"공지 1건":{"description":"공지 1건","value":{"success":true,"data":{"content":[{"id":7,"boardType":"notice","subject":"추석 연휴 배송 안내","contents":"9/24~9/27 은 택배 배송이 중단됩니다.","viewCount":132,"regDate":"2026-09-09T11:00:00.1"}],"pageable":{"pageNumber":0,"pageSize":20,"sort":{"empty":true,"sorted":false,"unsorted":true},"offset":0,"paged":true,"unpaged":false},"last":true,"totalElements":1,"totalPages":1,"size":20,"number":0,"sort":{"empty":true,"sorted":false,"unsorted":true},"first":true,"numberOfElements":1,"empty":false}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePagePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/bbs/notices/detail":{"get":{"tags":["게시판(앱)"],"summary":"공지사항 상세","description":"앱 공지 상세 화면(NoticeDetail)에서 호출한다. 식별자는 쿼리 id. 호출할 때마다 조회수(viewCount)가 1 증가한다. 삭제된 글이나 공지가 아닌 글은 COMMON_003. 로그인 불필요.","operationId":"notice","parameters":[{"name":"id","in":"query","description":"공지 게시글 id","required":true,"schema":{"type":"integer","format":"int64"},"example":7}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/bbs/faqs":{"get":{"tags":["게시판(앱)"],"summary":"FAQ 목록","description":"앱 FAQ 화면(Faq)과 관리자웹 FAQ 관리에서 호출한다. 각 항목에 categoryId 와 categoryName 이 포함되어 앱이 카테고리 탭으로 묶어 보여준다. categoryId 를 주면 그 카테고리만, 안 주면 전체를 돌려준다(관리자웹 카테고리 필터). 기본 페이지 크기 50. 로그인 불필요.","operationId":"faqs","parameters":[{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":50},"example":50},{"name":"categoryId","in":"query","description":"선택 — 카테고리 id (GET /api/v1/bbs/faq-categories 의 id). 없으면 전체","required":false,"schema":{"type":"integer","format":"int64"},"example":3}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePagePostView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/bbs/faq-categories":{"get":{"tags":["게시판(앱)"],"summary":"FAQ 카테고리 목록","description":"앱 FAQ 화면(Faq)의 카테고리 탭 구성용. 활성 카테고리만 정렬순(sort)으로 돌려준다. 로그인 불필요.","operationId":"faqCategories","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCategoryView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/app/setting":{"get":{"tags":["앱 설정"],"summary":"앱 부팅 설정 조회","description":"앱 로딩 화면(Loading)이 시작할 때마다 호출한다. platform 은 android 또는 ios(그 외는 COMMON_001). 응답 키는 RN 호환을 위해 snake_case 이며 up_bool/agree_bool/popup_bool/server_bool 값에 따라 앱이 차단 모달을 띄운다. 해당 플랫폼 행이 없으면 모든 플래그가 꺼진 기본 행을 자동 생성해 돌려준다. 로그인 불필요.","operationId":"get","parameters":[{"name":"platform","in":"query","description":"플랫폼: android | ios","required":false,"schema":{"type":"string","default":"android"},"example":"android"}],"responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"android, 강제 업데이트 켜짐":{"description":"android, 강제 업데이트 켜짐","value":{"success":true,"data":{"platform":"android","up_bool":"yes","up_build":120,"up_img":"/uploads/setting/update.png","up_img_width":300,"up_img_height":400,"agree_bool":"no","agree_no":3,"popup_bool":"no","server_bool":"no"}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAppSettingView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}},"/api/v1/admin/substitute-medicines":{"get":{"tags":["관리자 / 대체약품"],"summary":"대체약품 검색","description":"keyword(약품명·코드·업체 부분 일치)와 hasSubstitute(true 면 대체약이 있는 행만)로 거른 페이징 목록. 관리자웹에 전용 화면은 아직 없다. perPage 는 1~100. 관리자 토큰 필요.","operationId":"search_1","parameters":[{"name":"keyword","in":"query","description":"검색어 (약품명·약품코드·업체명 부분 일치)","required":false,"schema":{"type":"string"},"example":"타이레놀"},{"name":"hasSubstitute","in":"query","description":"대체약 존재 여부 필터 (true / false, 미지정 = 전체)","required":false,"schema":{"type":"boolean"},"example":true},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageSubstituteMedicineView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/substitute-medicines/lookup":{"get":{"tags":["관리자 / 대체약품"],"summary":"약품코드로 대체약 조회","description":"관리자웹 처방전 상세의 대체약 조회 팝업에서 호출한다. 쿼리 medicineCode(처방전 약품코드 = 품목코드)와 정확히 일치하는 원처방 행을 모두 돌려주며, 각 행의 substitute* 필드가 대체 약품이다(hasSubstitute=false 면 대체약 없음). 빈 값이면 빈 배열. 관리자 토큰 필요.","operationId":"lookup","parameters":[{"name":"medicineCode","in":"query","description":"처방전 약품코드 (품목코드, 정확 일치)","required":true,"schema":{"type":"string"},"example":641102470}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListSubstituteMedicineView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/substitute-medicines/detail":{"get":{"tags":["관리자 / 대체약품"],"summary":"대체약품 상세","description":"식별자는 쿼리 id(대체약품 행 id). 원처방 약품·3개월/월 사용량·대체 약품·수수료율을 한 행으로 돌려주며 없으면 COMMON_003. 관리자 토큰 필요.","operationId":"detail_2","parameters":[{"name":"id","in":"query","description":"대체약품 행 id","required":true,"schema":{"type":"integer","format":"int64"},"example":120}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseSubstituteMedicineView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/settings":{"get":{"tags":["관리자 / 건강샵"],"summary":"운영 설정 조회 (배송비 정책)","description":"관리자웹 운영 설정 메뉴에서 호출한다. 앱과 같은 값(deliveryFee, freeThreshold)을 돌려준다. SYSTEM_ADMIN 토큰 필요.","operationId":"getSettings_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseSettingView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/products":{"get":{"tags":["관리자 / 건강샵"],"summary":"상품 전체 목록","description":"관리자웹 상품 관리 메뉴의 목록. 숨김(visible=false) 상품까지 포함해 최신 등록순으로 돌려주되 삭제된 상품은 제외한다. SYSTEM_ADMIN 토큰 필요.","operationId":"getProducts_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListProductView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/shop/orders":{"get":{"tags":["관리자 / 건강샵"],"summary":"건강샵 주문 전체 목록","description":"관리자웹 건강샵 주문 관리 메뉴의 목록. 모든 회원의 주문을 최신순으로 돌려준다(페이징 없음). id 는 주문번호(SO-YYYYMMDD-###), memberId 는 회원 로그인 아이디. SYSTEM_ADMIN 토큰 필요.","operationId":"getOrders","responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"주문 1건":{"description":"주문 1건","value":{"success":true,"data":[{"id":"SO-20260911-001","date":"2026-09-11","memberId":"hong123","status":"PAID","statusLabel":"결제 완료","deliveryFee":3000,"total":18900,"items":[{"productId":"HP-001","productName":"비타민C 1000","quantity":1,"price":15900}],"delivery":{"name":"홍길동","phone":"010-1234-5678","zipcode":"06578","address":"서울특별시 서초구 반포대로 45","detailAddress":"101동 202호","memo":"문 앞에 놓아주세요"}}]}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListOrderView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/roles/menus":{"get":{"tags":["관리자 / 메뉴·권한관리"],"summary":"권한별 메뉴 목록","description":"권한관리 화면. 권한 목록은 코드그룹 admin_role 을 그대로 쓰며, 권한마다 허용된 메뉴코드 목록이 함께 내려간다. roleCode 를 주면 그 권한 하나만. SYSTEM_ADMIN 토큰 필요.","operationId":"listRoleMenus","parameters":[{"name":"roleCode","in":"query","description":"선택 — roleCode = 권한 코드. 없으면 전체 권한","required":false,"schema":{"type":"string"},"example":"PHARMACY_ADMIN"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListRoleMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/prescriptions":{"get":{"tags":["관리자 / 처방전"],"summary":"처방전 검색","description":"관리자웹 처방전 관리 메뉴의 목록. status(상태코드 01~010)와 keyword 로 거르고 약국 범위(scope)는 토큰의 역할로 자동 적용된다. PHARMACY_ADMIN 인데 매핑 약국이 없으면 빈 목록. 각 행에 회원 아이디·이름(memId/memName)과 약품 목록, 인식 정보가 포함된다. perPage 는 1~100. 관리자 토큰 필요.","operationId":"search_2","parameters":[{"name":"status","in":"query","description":"상태코드 필터: 01 발송 | 02 조제가능 | 03 조제불가 | 04 결제완료 | 05 조제완료 | 06 배송중 | 07 배송완료 | 08 미방문 | 09 오류 | 010 수령완료","required":false,"schema":{"type":"string"},"example":"02"},{"name":"keyword","in":"query","description":"검색어 (회원 이름·연락처·약국명 등 부분 일치)","required":false,"schema":{"type":"string"},"example":"홍길동"},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePagePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/prescriptions/detail":{"get":{"tags":["관리자 / 처방전"],"summary":"처방전 상세","description":"관리자웹 처방전 관리 메뉴의 상세/크게보기 모달에서 호출한다. 식별자는 쿼리 id(처방전 id). 없으면 COMMON_003, 소속 약국 밖이면 AUTH_005. 이미지 URL, 약사 메모, 단계별 진입 시각(readyAt/paidAt/preparedAt/inTransitAt/deliveredAt/pickedUpAt), 약품 목록, 병원·의사 인식 정보(partnerInfo)를 모두 포함한다. 관리자 토큰 필요.","operationId":"detail_3","parameters":[{"name":"id","in":"query","description":"처방전 id","required":true,"schema":{"type":"integer","format":"int64"},"example":41}],"responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"택배 배송중 처방전":{"description":"택배 배송중 처방전","value":{"success":true,"data":{"id":41,"status":"06","statusName":"배송중","receiveType":"onLine","prescriptionPrice":12500,"deliveryPrice":3000,"totalPrice":15500,"medicineDirection":"1일 3회 식후 30분 복용","pharmacistMemo":"재고 확인 완료","qrValue":"OCR","prescriptionImageUrl":"/uploads/prescription/12/2026-09-10/3f2a9c__rx.jpg","pharmacyName":"약나루약국","pharmacyPhone":"02-1234-5678","pharmacyAddress":"서울특별시 강남구 테헤란로 123 1층","memId":"hong123","memName":"홍길동","deliveryName":"홍길동","deliveryPhone":"010-1234-5678","deliveryAddress":"서울특별시 서초구 반포대로 45","deliveryDetailAddress":"101동 202호","deliveryNumber":"123456789012","deliveryCompany":"CJ대한통운","reqDate":"2026-09-10T09:12:33.481","readyAt":"2026-09-10T09:40:02.1","paidAt":"2026-09-10T10:05:47.32","inTransitAt":"2026-09-11T08:30:00.5","medicineList":[{"drgCd":"641102470","drgNm":"타이레놀정500밀리그램","dosage":"1","daysTotal":"3"}],"partnerInfo":{"seq":15,"hospitalName":"서울내과의원","hospitalPhone":"02-555-1234","doctorName":"이의사","doctorLicenseNo":"98765","patientName":"홍길동","departmentCode":"01","diagnosisCode1":"J00","prescriptionDate":"2026-09-10","useDays":"3"}}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePrescriptionView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/documents":{"get":{"tags":["관리자 / 약국"],"summary":"약국 첨부 서류 목록","description":"관리자웹 약국 관리 상세 모달의 사업자등록증/기타 서류 카드에서 호출한다. 식별자는 쿼리 code(약국 코드). 약사 회원가입 때 올린 사업자등록증 등을 fileUrl(/uploads/...)과 함께 등록순으로 돌려준다. SYSTEM_ADMIN 토큰 필요.","operationId":"documents","parameters":[{"name":"code","in":"query","description":"약국 코드","required":true,"schema":{"type":"string"},"example":"PH-012"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListPharmacyDocumentView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/pharmacies/admins":{"get":{"tags":["관리자 / 약국"],"summary":"약국에 매핑된 약사 계정 목록","description":"관리자웹 약국 관리 상세 모달의 약사 회원정보 카드에서 호출한다. 식별자는 쿼리 code(약국 코드). 매핑된 관리자 계정을 상태(PENDING/ACTIVE 등)와 함께 돌려주며 각 항목의 pharmacies 는 비어 있다. SYSTEM_ADMIN 토큰 필요.","operationId":"mappedAdmins","parameters":[{"name":"code","in":"query","description":"약국 코드","required":true,"schema":{"type":"string"},"example":"PH-001"}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAdminUserSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/orders":{"get":{"tags":["관리자 / 주문·매출"],"summary":"주문 검색","description":"관리자웹 주문 관리 메뉴의 목록. status(상태코드), pharmacyId(약국 PK), 접수일 범위 dateFrom~dateTo(yyyy-MM-dd, dateTo 당일 포함)로 거르고 약국 범위는 토큰 역할로 자동 적용된다. 행은 Excel 변환이 쉬운 평탄한 형태(회원명·연락처는 배송지 스냅샷). perPage 는 1~100. 관리자 토큰 필요.","operationId":"search_3","parameters":[{"name":"status","in":"query","description":"상태코드 필터 (01~010)","required":false,"schema":{"type":"string"},"example":"010"},{"name":"pharmacyId","in":"query","description":"약국 PK (코드 아님)","required":false,"schema":{"type":"integer","format":"int64"},"example":3},{"name":"dateFrom","in":"query","description":"접수일 시작 (yyyy-MM-dd)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-01"},{"name":"dateTo","in":"query","description":"접수일 끝 (yyyy-MM-dd, 당일 포함)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-30"},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageAdminOrderRow"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/orders/revenue":{"get":{"tags":["관리자 / 주문·매출"],"summary":"약국별 매출 정산","description":"관리자웹 매출 정산 메뉴에서 호출한다. status 기본값은 010(수령완료)이며 날짜 범위(접수일 기준)를 비우면 전체 기간. 약국별 주문 수·총액·조제비 합·배송비 합(rows)과 전체 합계(totalOrderCount, totalRevenueSum)를 돌려준다. 약국 범위는 토큰 역할로 자동 적용. 관리자 토큰 필요.","operationId":"revenue","parameters":[{"name":"status","in":"query","description":"집계 대상 상태코드 (기본 010 수령완료)","required":false,"schema":{"type":"string","default":"010"},"example":"010"},{"name":"dateFrom","in":"query","description":"접수일 시작 (yyyy-MM-dd)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-01"},{"name":"dateTo","in":"query","description":"접수일 끝 (yyyy-MM-dd, 당일 포함)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-30"}],"responses":{"200":{"description":"집계 성공","content":{"application/json":{"examples":{"약국 2곳":{"description":"약국 2곳","value":{"success":true,"data":{"rows":[{"pharmacyId":3,"pharmacyName":"약나루약국","orderCount":31,"totalSum":842000,"prescriptionSum":749000,"deliverySum":93000},{"pharmacyId":5,"pharmacyName":"건강약국","orderCount":17,"totalSum":408000,"prescriptionSum":372000,"deliverySum":36000}],"totalOrderCount":48,"totalRevenueSum":1250000,"dateFrom":"2026-09-01","dateTo":"2026-09-30","status":"010"}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminRevenueSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/orders/revenue/export.xlsx":{"get":{"tags":["관리자 / 주문·매출"],"summary":"매출 정산 Excel 다운로드","description":"관리자웹 매출 정산 메뉴의 Excel 버튼. 매출 정산 조회와 같은 집계를 xlsx 파일(revenue-yyyy-MM-dd.xlsx)로 내려준다. 응답은 공통 JSON 래퍼가 아닌 바이너리다. 관리자 토큰 필요.","operationId":"exportRevenue","parameters":[{"name":"status","in":"query","description":"집계 대상 상태코드 (기본 010 수령완료)","required":false,"schema":{"type":"string","default":"010"},"example":"010"},{"name":"dateFrom","in":"query","description":"접수일 시작 (yyyy-MM-dd)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-01"},{"name":"dateTo","in":"query","description":"접수일 끝 (yyyy-MM-dd, 당일 포함)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-30"}],"responses":{"200":{"description":"xlsx 파일","content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/orders/export.xlsx":{"get":{"tags":["관리자 / 주문·매출"],"summary":"주문 목록 Excel 다운로드","description":"관리자웹 주문 관리 메뉴의 Excel 버튼. 검색과 같은 필터를 받되 페이징 없이 최대 100,000 행을 xlsx 파일(orders-yyyy-MM-dd.xlsx, Content-Disposition attachment)로 내려준다. 응답은 공통 JSON 래퍼가 아닌 바이너리다. 관리자 토큰 필요.","operationId":"exportOrders","parameters":[{"name":"status","in":"query","description":"상태코드 필터 (01~010)","required":false,"schema":{"type":"string"},"example":"010"},{"name":"pharmacyId","in":"query","description":"약국 PK","required":false,"schema":{"type":"integer","format":"int64"},"example":3},{"name":"dateFrom","in":"query","description":"접수일 시작 (yyyy-MM-dd)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-01"},{"name":"dateTo","in":"query","description":"접수일 끝 (yyyy-MM-dd, 당일 포함)","required":false,"schema":{"type":"string","format":"date"},"example":"2026-09-30"}],"responses":{"200":{"description":"xlsx 파일","content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/orders/detail":{"get":{"tags":["관리자 / 주문·매출"],"summary":"주문 상세","description":"관리자웹 주문 관리 메뉴의 상세 모달에서 호출한다. 식별자는 쿼리 id(처방전 id). 앱 주문 상세와 같은 형태이며 없으면 COMMON_003, 소속 약국 밖이면 AUTH_005. 관리자 토큰 필요.","operationId":"detail_4","parameters":[{"name":"id","in":"query","description":"처방전(주문) id","required":true,"schema":{"type":"integer","format":"int64"},"example":41}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseOrderDetail"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/menus":{"get":{"tags":["관리자 / 메뉴·권한관리"],"summary":"전체 메뉴 트리","description":"메뉴관리 화면 목록. 미사용 메뉴까지 모두, 상위 메뉴 안에 children 으로 하위 메뉴가 담겨 내려간다. SYSTEM_ADMIN 토큰 필요.","operationId":"listMenus","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/menus/my":{"get":{"tags":["관리자 / 메뉴·권한관리"],"summary":"내 사이드바 메뉴","description":"로그인한 관리자의 권한으로 볼 수 있는 메뉴 트리. 사용여부 Y 이면서 내 권한에 허용된 메뉴만 내려간다. 하위 메뉴가 모두 막힌 상위 메뉴는 빠진다. 관리자웹이 로그인 직후 호출한다. 관리자 토큰 필요.","operationId":"myMenus","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListMyMenuView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/members":{"get":{"tags":["관리자 / 회원"],"summary":"회원 검색","description":"관리자웹 회원 관리(앱) 메뉴의 목록. keyword 와 state(ACTIVE/DORMANT/SUSPENDED/WITHDRAWN)로 거르고 withDeleted=true 면 탈퇴 회원도 포함한다. perPage 는 1~100 으로 보정. SYSTEM_ADMIN 토큰 필요.","operationId":"search_4","parameters":[{"name":"keyword","in":"query","description":"검색어 (아이디·이름·이메일·전화 부분 일치)","required":false,"schema":{"type":"string"},"example":"hong"},{"name":"state","in":"query","description":"상태 필터: ACTIVE | DORMANT | SUSPENDED | WITHDRAWN","required":false,"schema":{"type":"string"},"example":"ACTIVE"},{"name":"withDeleted","in":"query","description":"탈퇴(삭제) 회원 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":false},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"검색 성공 (Spring Data Page 형태)","content":{"application/json":{"examples":{"회원 1건":{"description":"회원 1건","value":{"success":true,"data":{"content":[{"id":12,"memId":"hong123","memName":"홍길동","memEmail":"hong@example.com","memTel":"010-1234-5678","memState":"ACTIVE","roles":["USER"],"createdAt":"2026-08-01T10:00:00.123"}],"pageable":{"pageNumber":0,"pageSize":20,"sort":{"empty":true,"sorted":false,"unsorted":true},"offset":0,"paged":true,"unpaged":false},"last":true,"totalElements":1,"totalPages":1,"size":20,"number":0,"sort":{"empty":true,"sorted":false,"unsorted":true},"first":true,"numberOfElements":1,"empty":false}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageAdminMemberSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/members/detail":{"get":{"tags":["관리자 / 회원"],"summary":"회원 상세","description":"관리자웹 회원 관리(앱) 메뉴의 상세 모달에서 호출한다. 식별자는 쿼리 id(회원 PK). 앱의 내 정보와 같은 형태이며 없으면 MEMBER_001. SYSTEM_ADMIN 토큰 필요.","operationId":"detail_5","parameters":[{"name":"id","in":"query","description":"회원 PK","required":true,"schema":{"type":"integer","format":"int64"},"example":12}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMemberInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/me":{"get":{"tags":["관리자 / 내 정보"],"summary":"내 정보 조회","description":"관리자웹 헤더와 내 정보 메뉴(myProfile)에서 호출한다. 역할(roles), 상태, 마지막 로그인 시각, 약사 생년월일(adminBirth, PHARMACY_ADMIN 만 의미)을 포함한다. 관리자 토큰 필요.","operationId":"me_1","responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"약사 계정":{"description":"약사 계정","value":{"success":true,"data":{"id":31,"adminId":"pharm_kim","adminName":"김약사","adminEmail":"kim@pharmacy.kr","adminTel":"010-1111-2222","adminBirth":"1985-03-02","adminState":"ACTIVE","roles":["PHARMACY_ADMIN"],"lastLoginAt":"2026-09-11T09:02:11.53","createdAt":"2026-08-20T14:10:00.2"}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMeInfo"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/me/pharmacies":{"get":{"tags":["관리자 / 내 정보"],"summary":"내 약국 목록","description":"관리자웹 약국정보 메뉴(pharmacyInfo, 약사 전용)에서 호출한다. 본인에게 매핑된 약국을 영업시간·약사·계좌 정보까지 포함해 돌려준다. 매핑이 없으면 빈 배열(SYSTEM_ADMIN 도 매핑이 있으면 표시). 관리자 토큰 필요.","operationId":"myPharmacies","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListPharmacyView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/eligibility":{"get":{"tags":["관리자 / 자격 심사"],"summary":"자격 신청 검색","description":"관리자웹 약 배송 자격 메뉴의 목록. state 로 I(심사중)/S(승인)/R(반려)만 거르거나 비우면 전체. 각 행에 회원 아이디·이름(memberLoginId/memberName)과 첨부 수(documentCount)가 포함된다. 잘못된 state 값은 COMMON_001. perPage 는 1~100. 관리자 토큰 필요.","operationId":"search_5","parameters":[{"name":"state","in":"query","description":"상태 필터: I 심사중 | S 승인 | R 반려 (미지정 = 전체)","required":false,"schema":{"type":"string"},"example":"I"},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageEligibilitySummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/eligibility/detail":{"get":{"tags":["관리자 / 자격 심사"],"summary":"자격 신청 상세","description":"관리자웹 약 배송 자격 메뉴의 상세 모달에서 호출한다. 식별자는 쿼리 id(신청 id). 첨부 서류 목록(fileUrl 은 /uploads/... 경로)을 포함하며 없으면 COMMON_003. 관리자 토큰 필요.","operationId":"detail_6","parameters":[{"name":"id","in":"query","description":"자격 신청 id","required":true,"schema":{"type":"integer","format":"int64"},"example":9}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseEligibilityDetail"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/drug-master/status":{"get":{"tags":["관리자 / 약품 마스터"],"summary":"약품 마스터 적재 현황","description":"관리자웹 약품 마스터 메뉴 상단 현황 카드에서 호출한다. 적재된 약품 수(count)와 가장 최근 적재 시각(lastLoadedAt, 없으면 생략)을 돌려준다. 관리자 토큰(SYSTEM_ADMIN 또는 PHARMACY_ADMIN) 필요.","operationId":"status","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseStatusView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/drug-master/lookup":{"get":{"tags":["관리자 / 약품 마스터"],"summary":"약품 코드 조회","description":"관리자웹 처방전 상세(크게보기)에서 약품코드 입력 시 약품명 자동 조회와 약품 마스터 메뉴의 검색에서 호출한다. 식별자는 쿼리 code(EDI 9자리 보험코드, 공백은 COMMON_001). 약품 마스터를 먼저 찾고(source=MASTER) 없으면 대체약품 자료의 원처방 약품명으로 대신하며(SUBSTITUTE), 둘 다 없으면 NONE. 같은 코드의 대체약품 목록(substitutes)을 항상 함께 돌려준다. 관리자 토큰 필요.","operationId":"lookup_1","parameters":[{"name":"code","in":"query","description":"EDI 약품코드 (9자리 숫자)","required":true,"schema":{"type":"string"},"example":641102470}],"responses":{"200":{"description":"조회 성공 (미등록 코드도 200 + source=NONE)","content":{"application/json":{"examples":{"마스터에 있음":{"description":"마스터에 있음","value":{"success":true,"data":{"ediCode":"641102470","name":"타이레놀정500밀리그램","company":"한국얀센","price":51,"source":"MASTER","substitutes":[]}}},"미등록 코드":{"description":"미등록 코드","value":{"success":true,"data":{"ediCode":"999999999","source":"NONE","substitutes":[]}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseDrugLookupView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/dashboard/summary":{"get":{"tags":["관리자 / 대시보드"],"summary":"대시보드 요약","description":"관리자웹 홈(대시보드) 진입 시 호출한다. counts: todayNew(오늘 접수된 01 발송 건, 최근 100건 내에서 집계) / paymentWaiting(02 조제가능) / shipping(06 배송중), monthRevenue·monthOrderCount(이번 달 1일~오늘, 010 수령완료 기준 매출·건수), recent(최근 처방전 5건, 상태 무관), asOf(집계 시각), period(집계 기간). 약국 범위는 토큰 역할로 자동 적용되며 매핑 약국이 없는 약사는 모두 0/빈 배열. 관리자 토큰 필요.","operationId":"summary","responses":{"200":{"description":"집계 성공","content":{"application/json":{"examples":{"9월 11일 집계":{"description":"9월 11일 집계","value":{"success":true,"data":{"counts":{"todayNew":3,"paymentWaiting":5,"shipping":2},"monthRevenue":1250000,"monthOrderCount":48,"recent":[{"id":42,"status":"01","statusName":"발송","receiveType":"onLine","pharmacyName":"약나루약국","pharmacyPhone":"02-1234-5678","pharmacyAddress":"서울특별시 강남구 테헤란로 123 1층","memId":"hong123","memName":"홍길동","deliveryName":"홍길동","deliveryPhone":"010-1234-5678","deliveryAddress":"서울특별시 서초구 반포대로 45","reqDate":"2026-09-11T10:15:30.123","medicineList":[]}],"asOf":"2026-09-11T10:20:01.554","period":{"from":"2026-09-01","to":"2026-09-11"}}}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseDashboardSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes":{"get":{"tags":["관리자 / 코드관리"],"summary":"그룹별 코드 목록","description":"코드관리 화면 오른쪽 코드 목록. groupCode 는 필수이며 없는 그룹이면 COMMON_003. 기본은 사용중 코드만, includeUnused=true 면 미사용 코드도 함께. 관리자 토큰 필요.","operationId":"listCodes_1","parameters":[{"name":"groupCode","in":"query","description":"groupCode = 코드 그룹","required":true,"schema":{"type":"string"},"example":"prescription_status"},{"name":"includeUnused","in":"query","description":"선택 — includeUnused = 미사용 코드 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":true}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCodeItemView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/groups":{"get":{"tags":["관리자 / 코드관리"],"summary":"코드 그룹 목록","description":"코드관리 화면 왼쪽 그룹 목록. 기본은 사용중(useYn=Y)인 그룹만, includeUnused=true 면 미사용 그룹도 함께. 각 행의 codeCount 는 그룹에 속한 코드 수. 관리자 토큰 필요.","operationId":"listGroups","parameters":[{"name":"includeUnused","in":"query","description":"선택 — includeUnused = 미사용 그룹 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":true}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCodeGroupView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/codes/all":{"get":{"tags":["관리자 / 코드관리"],"summary":"전체 코드 묶음","description":"관리자웹이 로그인 직후 한 번 받아 캐시하는 전체 코드. 응답은 {그룹코드: [코드...]} 형태라 화면이 상태·구분 이름을 그릴 때 서버를 다시 부르지 않는다. 기본은 사용중 코드만. 관리자 토큰 필요.","operationId":"allCodes","parameters":[{"name":"includeUnused","in":"query","description":"선택 — includeUnused = 미사용 코드 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":false}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringListCodeItemView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/{board}-categories":{"get":{"tags":["관리자 / 게시판"],"summary":"카테고리 목록","description":"관리자웹 카테고리 메뉴와 FAQ/QnA 등록 모달의 선택 목록. 경로의 board 는 faq 또는 qna. includeInactive=true 면 비활성 카테고리도 포함한다. SYSTEM_ADMIN 토큰 필요.","operationId":"listCategories","parameters":[{"name":"board","in":"path","description":"게시판 종류: faq | qna","required":true,"schema":{"type":"string"},"example":"faq"},{"name":"includeInactive","in":"query","description":"비활성 카테고리 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":false}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListCategoryView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/qnas":{"get":{"tags":["관리자 / 게시판"],"summary":"QnA 목록","description":"관리자웹 QnA 답변 메뉴의 목록. status 로 WAITING(답변대기)/ANSWERED(답변완료)만 거르거나 비우면 전체(그 외 값은 COMMON_001). 응답의 status 는 한글 라벨. perPage 는 1~100. SYSTEM_ADMIN 토큰 필요.","operationId":"listQnas","parameters":[{"name":"status","in":"query","description":"상태 필터: WAITING | ANSWERED (미지정 = 전체)","required":false,"schema":{"type":"string"},"example":"WAITING"},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기 (최대 100)","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageQnaView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/bbs/qnas/detail":{"get":{"tags":["관리자 / 게시판"],"summary":"QnA 상세","description":"관리자웹 QnA 답변 메뉴의 답변 모달에서 호출한다. 식별자는 쿼리 id(문의 글 id). 질문·기존 답변·작성 회원 id 를 돌려주며 삭제되었거나 QnA 가 아니면 COMMON_003. SYSTEM_ADMIN 토큰 필요.","operationId":"getQna","parameters":[{"name":"id","in":"query","description":"문의 글 id","required":true,"schema":{"type":"integer","format":"int64"},"example":15}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseQnaView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users":{"get":{"tags":["관리자 / 관리자 계정"],"summary":"관리자 계정 검색","description":"관리자웹 관리자 계정 메뉴의 목록. keyword(아이디·이름 등), role, state 로 거르고 withDeleted=true 면 탈퇴 계정도 포함한다. 각 행에 매핑 약국 목록(pharmacies, 첨부 서류 수 포함)이 채워진다. SYSTEM_ADMIN 토큰 필요.","operationId":"search_6","parameters":[{"name":"keyword","in":"query","description":"검색어 (아이디·이름·이메일 부분 일치)","required":false,"schema":{"type":"string"},"example":"kim"},{"name":"role","in":"query","description":"역할 필터: SYSTEM_ADMIN | PHARMACY_ADMIN","required":false,"schema":{"type":"string","enum":["PHARMACY_ADMIN","SYSTEM_ADMIN"]},"example":"PHARMACY_ADMIN"},{"name":"state","in":"query","description":"상태 필터: PENDING | ACTIVE | SUSPENDED | WITHDRAWN","required":false,"schema":{"type":"string","enum":["PENDING","ACTIVE","SUSPENDED","WITHDRAWN"]},"example":"PENDING"},{"name":"withDeleted","in":"query","description":"탈퇴(삭제) 계정 포함 여부","required":false,"schema":{"type":"boolean","default":false},"example":false},{"name":"page","in":"query","description":"페이지 번호(0부터)","required":false,"schema":{"type":"integer","format":"int32","default":0},"example":0},{"name":"perPage","in":"query","description":"페이지 크기","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":20}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponsePageAdminUserSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/pending-count":{"get":{"tags":["관리자 / 관리자 계정"],"summary":"가입 대기 약사 수","description":"관리자웹 헤더 뱃지가 주기적으로 호출한다. 상태 PENDING 인 관리자 계정 수를 {count} 로 돌려주며 60초 인메모리 캐시라 승인/반려 직후 최대 60초 늦게 반영될 수 있다. SYSTEM_ADMIN 토큰 필요.","operationId":"pendingCount","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringLong"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/admin/admin-users/detail":{"get":{"tags":["관리자 / 관리자 계정"],"summary":"관리자 계정 상세","description":"관리자웹 관리자 계정 메뉴의 상세/수정 모달에서 호출한다. 식별자는 쿼리 id(관리자 PK). 매핑 약국 목록을 포함하며 없으면 COMMON_003. SYSTEM_ADMIN 토큰 필요.","operationId":"get_1","parameters":[{"name":"id","in":"query","description":"관리자 PK (admin_user.admin_id)","required":true,"schema":{"type":"integer","format":"int64"},"example":31}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseAdminUserSummary"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/addresses":{"get":{"tags":["배송지(앱)"],"summary":"내 배송지 목록","description":"앱 배송지 관리 화면(AddressManagement)과 약 주문 시작 화면(OrderMedicineMain)의 배송지 선택에서 호출한다. 삭제되지 않은 본인 배송지만 반환하며 기본 배송지(isDefault=true)가 먼저, 그다음 최근 등록순이다. 회원 토큰 필요.","operationId":"list","responses":{"200":{"description":"조회 성공","content":{"application/json":{"examples":{"배송지 2건":{"description":"배송지 2건","value":{"success":true,"data":[{"deliveryAddressSeq":5,"deliveryAddressName":"홍길동","deliveryAddressPhone":"010-1234-5678","deliveryAddressZipcode":"06578","deliveryAddress":"서울특별시 서초구 반포대로 45","deliveryDetailAddress":"101동 202호","roadName":"반포대로","isDefault":true},{"deliveryAddressSeq":3,"deliveryAddressName":"홍길동(회사)","deliveryAddressPhone":"010-1234-5678","deliveryAddressZipcode":"06236","deliveryAddress":"서울특별시 강남구 테헤란로 123","deliveryDetailAddress":"7층","roadName":"테헤란로","isDefault":false}]}}}},"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseListAddressView"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}},"401":{"description":"인증 실패 (토큰 없음 AUTH_001 / 만료 AUTH_003 / 위조 AUTH_004)","content":{"application/json":{"examples":{"AUTH_001":{"summary":"AUTH_001","value":{"error":{"code":"AUTH_001","message":"인증이 필요합니다."},"success":false}}}}}},"403":{"description":"권한 없음 (역할 부족, 다른 종류의 토큰, 타인 자원 접근)","content":{"application/json":{"examples":{"AUTH_005":{"summary":"AUTH_005","value":{"error":{"code":"AUTH_005","message":"권한이 없습니다."},"success":false}}}}}}},"security":[{"bearerAuth":[]}]}},"/":{"get":{"tags":["헬스 체크"],"summary":"서버 상태 확인","description":"서비스명, 상태(UP), 서버 현재 시각을 돌려준다. DB 연결은 확인하지 않으며(그건 /actuator/health), 프로세스가 요청을 받는지만 본다. 로그인 불필요.","operationId":"root","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiResponseMapStringObject"}}}},"400":{"description":"잘못된 요청 (필수값 누락, 형식·검증 실패, 알 수 없는 코드값, 깨진 JSON·UTF-8 아닌 인코딩)","content":{"application/json":{"examples":{"COMMON_001":{"summary":"COMMON_001","value":{"error":{"code":"COMMON_001","message":"memId: 아이디를 입력해 주세요."},"success":false}}}}}}},"security":[]}}},"components":{"schemas":{"DeliveryRequest":{"type":"object","description":"건강샵 배송지 요청 — 주문 생성 요청의 delivery","properties":{"name":{"type":"string","description":"name = 받는 분 이름","example":"홍길동","minLength":1},"phone":{"type":"string","description":"phone = 받는 분 연락처","example":"010-1234-5678","minLength":1},"zipcode":{"type":"string","description":"선택 — zipcode = 우편번호 (5자리)","example":48058},"address":{"type":"string","description":"address = 배송 기본 주소","example":"부산광역시 해운대구 센텀중앙로 79","minLength":1},"detailAddress":{"type":"string","description":"선택 — detailAddress = 배송 상세 주소 (동/호수)","example":"101동 1203호"},"memo":{"type":"string","description":"선택 — memo = 배송 요청사항","example":"부재 시 문 앞에 놓아주세요."}},"required":["address","name","phone"]},"OrderCreateRequest":{"type":"object","description":"건강샵 주문 생성 요청 — POST /api/v1/shop/orders/create (결제 승인 후 호출, 주문번호 SO-YYYYMMDD-### 자동 채번)","properties":{"items":{"type":"array","description":"items = 주문 상품 목록 (1개 이상)","items":{"$ref":"#/components/schemas/OrderItemRequest"},"minItems":1},"delivery":{"$ref":"#/components/schemas/DeliveryRequest","description":"선택 — delivery = 배송지 정보"}},"required":["items"]},"OrderItemRequest":{"type":"object","description":"건강샵 주문 상품 요청 1건 — 주문 생성 요청의 items 항목","properties":{"productId":{"type":"string","description":"productId = 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식)","example":"HP-001","minLength":1},"quantity":{"type":"integer","format":"int32","description":"quantity = 주문 수량 (1 이상)","example":2}},"required":["productId"]},"ApiResponseOrderView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/OrderView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"DeliveryView":{"type":"object","description":"건강샵 배송지 정보 — 주문 뷰의 delivery","properties":{"name":{"type":"string","description":"name = 받는 분 이름","example":"홍길동"},"phone":{"type":"string","description":"phone = 받는 분 연락처","example":"010-1234-5678"},"zipcode":{"type":"string","description":"선택 — zipcode = 우편번호 (5자리)","example":48058},"address":{"type":"string","description":"address = 배송 기본 주소","example":"부산광역시 해운대구 센텀중앙로 79"},"detailAddress":{"type":"string","description":"선택 — detailAddress = 배송 상세 주소 (동/호수)","example":"101동 1203호"},"memo":{"type":"string","description":"선택 — memo = 배송 요청사항","example":"부재 시 문 앞에 놓아주세요."}}},"ErrorBody":{"type":"object","description":"오류 정보 — HTTP 상태코드와 함께 온다","properties":{"code":{"type":"string","description":"code = 오류 코드 — COMMON_001 / AUTH_001 / MEMBER_002 … (Swagger 상단 표 참고)","example":"COMMON_001"},"message":{"type":"string","description":"message = 사용자에게 그대로 보여줄 한국어 문장","example":"addressId: 수정할 배송지를 선택해 주세요."}}},"Meta":{"type":"object","description":"목록 페이지 정보","properties":{"page":{"type":"integer","format":"int32","description":"page = 현재 페이지 (0부터)","example":0},"perPage":{"type":"integer","format":"int32","description":"perPage = 페이지 크기","example":20},"total":{"type":"integer","format":"int64","description":"total = 전체 건수","example":57}}},"OrderItemView":{"type":"object","description":"건강샵 주문 상품 1건 — 주문 뷰의 items 항목 (주문 시점 스냅샷)","properties":{"productId":{"type":"string","description":"productId = 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식)","example":"HP-001"},"productName":{"type":"string","description":"productName = 상품명 (주문 시점 스냅샷)","example":"멀티비타민 미네랄 90정"},"quantity":{"type":"integer","format":"int32","description":"quantity = 주문 수량","example":2},"price":{"type":"integer","format":"int32","description":"price = 단가 (원, 주문 시점 스냅샷)","example":24900}}},"OrderView":{"type":"object","description":"건강샵 주문 — GET /api/v1/shop/orders, POST /api/v1/shop/orders/create 응답, 관리자 GET /api/v1/admin/shop/orders 항목","properties":{"id":{"type":"string","description":"id = 주문번호 (SO-YYYYMMDD-### 형식) — 관리자 상태 변경 요청의 orderNo","example":"SO-20260911-001"},"date":{"type":"string","description":"date = 주문 일자 (YYYY-MM-DD)","example":"2026-09-11"},"memberId":{"type":"string","description":"memberId = 주문 회원 로그인 아이디","example":"hong1234"},"status":{"type":"string","description":"status = 주문 상태 코드 — PAID 결제 완료 / SHIPPING 배송 중 / DELIVERED 배송 완료","example":"PAID"},"statusLabel":{"type":"string","description":"statusLabel = 주문 상태 한글 라벨 — 결제 완료 / 배송 중 / 배송 완료","example":"결제 완료"},"deliveryFee":{"type":"integer","format":"int32","description":"deliveryFee = 적용 배송비 (원) — 무료 배송 기준 이상이면 0","example":3000},"total":{"type":"integer","format":"int32","description":"total = 총 결제 금액 (원, 상품 합계 + 배송비)","example":52800},"items":{"type":"array","description":"items = 주문 상품 목록","items":{"$ref":"#/components/schemas/OrderItemView"}},"delivery":{"$ref":"#/components/schemas/DeliveryView","description":"delivery = 배송지 정보"}}},"UnsubscribeRequest":{"type":"object","description":"푸시 토큰 구독 해제 요청 — POST /api/v1/push/unsubscribe","properties":{"fcmToken":{"type":"string","description":"fcmToken = 해제할 FCM 디바이스 토큰 — 구독 시 전송한 값","example":"dXk9f3…:APA91bH…","minLength":1}},"required":["fcmToken"]},"ApiResponseVoid":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"SubscribeRequest":{"type":"object","description":"푸시 토큰 구독 요청 — POST /api/v1/push/subscribe (동일 토큰 재전송 시 메타 갱신)","properties":{"fcmToken":{"type":"string","description":"fcmToken = Firebase Cloud Messaging 디바이스 토큰","example":"dXk9f3…:APA91bH…","minLength":1},"deviceId":{"type":"string","description":"선택 — deviceId = 단말 식별자 (앱이 생성한 고유값)","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","description":"선택 — platform = 단말 플랫폼 — android / ios","example":"android"}},"required":["fcmToken"]},"ApiResponseSubscriptionInfo":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/SubscriptionInfo","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"SubscriptionInfo":{"type":"object","description":"푸시 토큰 구독 정보 — POST /api/v1/push/subscribe 응답","properties":{"id":{"type":"integer","format":"int64","description":"id = 구독(토큰) PK (push_token.token_id)","example":14},"deviceId":{"type":"string","description":"선택 — deviceId = 단말 식별자","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","description":"선택 — platform = 단말 플랫폼 — android / ios","example":"android"},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 최초 구독 일시 (ISO-8601)","example":"2026-09-01T10:00:00"},"updatedAt":{"type":"string","format":"date-time","description":"updatedAt = 마지막 갱신 일시 (ISO-8601)","example":"2026-09-11T09:30:00"}}},"SendRequest":{"type":"object","description":"관리자 푸시 발송 요청 — POST /api/v1/push/send (memberId 없으면 전체 발송)","properties":{"memberId":{"type":"integer","format":"int64","description":"선택 — memberId = 수신 회원 PK — GET /api/v1/admin/members 목록의 id, null = 전체 발송(broadcast)","example":7},"title":{"type":"string","description":"title = 알림 제목","example":"추석 연휴 배송 안내","minLength":1},"body":{"type":"string","description":"body = 알림 본문","example":"연휴 기간 택배 배송이 지연될 수 있습니다.","minLength":1},"payload":{"type":"string","description":"선택 — payload = 앱 딥링크용 부가 데이터 (JSON 문자열)","example":{"screen":"NoticeDetail","id":15}},"relatedType":{"type":"string","description":"선택 — relatedType = 연관 대상 유형 — order / delivery / eligibility / notice 등","example":"notice"},"relatedId":{"type":"integer","format":"int64","description":"선택 — relatedId = 연관 대상 PK","example":15}},"required":["body","title"]},"ApiResponseMapStringLong":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MessageReadRequest":{"type":"object","description":"알림 1건 읽음 처리 요청 — POST /api/v1/push/messages/read","properties":{"pushId":{"type":"integer","format":"int64","description":"pushId = 알림 PK — GET /api/v1/push/messages 목록의 id","example":88}},"required":["pushId"]},"ApiResponseMapStringInteger":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"object","additionalProperties":{"type":"integer","format":"int32"},"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MessageDeleteRequest":{"type":"object","description":"알림 1건 삭제 요청 — POST /api/v1/push/messages/delete","properties":{"pushId":{"type":"integer","format":"int64","description":"pushId = 알림 PK — GET /api/v1/push/messages 목록의 id","example":88}},"required":["pushId"]},"CreatePrescriptionRequest":{"type":"object","description":"처방전 등록(주문 생성) 요청 — POST /api/v1/prescriptions (이미지 업로드·QR/OCR 콜백 결과를 묶어 저장)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 조제 요청 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001","minLength":1},"receiveType":{"type":"string","description":"선택 — receiveType = 수령 방식 — onLine 택배배송 / offLine 방문수령","example":"onLine"},"deliveryAddressId":{"type":"integer","format":"int64","description":"선택 — deliveryAddressId = 배송지 PK — GET /api/v1/addresses 의 deliveryAddressSeq, onLine 일 때","example":12},"deliveryName":{"type":"string","description":"선택 — deliveryName = 수령인 이름 (onLine 스냅샷)","example":"홍길동"},"deliveryPhone":{"type":"string","description":"선택 — deliveryPhone = 수령인 연락처 (onLine 스냅샷)","example":"010-1234-5678"},"deliveryAddress":{"type":"string","description":"선택 — deliveryAddress = 배송 기본 주소 (onLine 스냅샷)","example":"부산광역시 해운대구 센텀중앙로 79"},"deliveryDetailAddress":{"type":"string","description":"선택 — deliveryDetailAddress = 배송 상세 주소 (동/호수)","example":"101동 1203호"},"prescriptionImagePath":{"type":"string","description":"선택 — prescriptionImagePath = 처방전 이미지 저장 경로 — POST /api/v1/prescriptions/upload-image 응답의 storagePath","example":"C:/DEV/.../uploads/prescription/7/2026-09-11/3f9c1a2b__rx.jpg"},"qrImagePath":{"type":"string","description":"선택 — qrImagePath = QR 영역 이미지 저장 경로 — upload-image 응답의 storagePath","example":"C:/DEV/.../uploads/prescription/7/2026-09-11/3f9c1a2b__qr.jpg"},"qrValue":{"type":"string","description":"qrValue = 처방전 QR 원문 (또는 OCR 식별값)","example":"PRS_ENC:9f3a2b1c…","minLength":1},"medicineSeq":{"type":"integer","format":"int64","description":"선택 — medicineSeq = 발급정보 PK — POST /api/v1/prescriptions/qr-callback 응답의 medicineSeq, null = 미인식","example":55}},"required":["pharmacyCode","qrValue"]},"ApiResponsePrescriptionView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PrescriptionView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MedicineView":{"type":"object","description":"처방 약품 1건 — 처방전 발급정보(issue_info)의 약품 라인","properties":{"drgCd":{"type":"string","description":"drgCd = 약품 코드 (EDI 보험코드 9자리)","example":640007270},"drgNm":{"type":"string","description":"drgNm = 약품명","example":"타이레놀정500mg"},"amount":{"type":"integer","format":"int32","description":"선택 — amount = 총 수량 — 현재 발급정보에 없어 항상 null","example":null},"dosage":{"type":"string","description":"선택 — dosage = 1회 투약량","example":1},"daysTotal":{"type":"string","description":"선택 — daysTotal = 총 투약 일수","example":3}}},"PartnerInfo":{"type":"object","description":"처방전 발급 정보 (issue_info) — 병원/의사/환자/진단/처방일, QR 디코드 또는 OCR 파싱 결과","properties":{"seq":{"type":"integer","format":"int64","description":"seq = 발급정보 PK (issue_info.issue_id) — POST /api/v1/prescriptions 의 medicineSeq 와 동일","example":55},"hospitalName":{"type":"string","description":"선택 — hospitalName = 의료기관 명칭","example":"부산대학교병원"},"hospitalPhone":{"type":"string","description":"선택 — hospitalPhone = 의료기관 전화번호","example":"051-240-7000"},"hospitalFax":{"type":"string","description":"선택 — hospitalFax = 의료기관 팩스번호","example":"051-240-7001"},"hospitalEmail":{"type":"string","description":"선택 — hospitalEmail = 의료기관 이메일","example":"info@pnuh.or.kr"},"doctorName":{"type":"string","description":"선택 — doctorName = 처방 의사 성명","example":"김의사"},"doctorLicenseType":{"type":"string","description":"선택 — doctorLicenseType = 의사 면허 종별 (발급사 코드값)","example":"의사"},"doctorLicenseNo":{"type":"string","description":"선택 — doctorLicenseNo = 의사 면허번호","example":98765},"patientName":{"type":"string","description":"선택 — patientName = 환자 성명","example":"홍길동"},"departmentCode":{"type":"string","description":"선택 — departmentCode = 진료과목 코드 (발급사 코드값)","example":"01"},"diagnosisCode1":{"type":"string","description":"선택 — diagnosisCode1 = 주상병 코드 (KCD)","example":"J06.9"},"diagnosisCode2":{"type":"string","description":"선택 — diagnosisCode2 = 부상병 코드 (KCD)","example":"R50.9"},"prescriptionDate":{"type":"string","description":"선택 — prescriptionDate = 처방전 교부일 (YYYY-MM-DD)","example":"2026-09-11"},"useDays":{"type":"string","description":"선택 — useDays = 처방전 사용기간 (일)","example":3},"linkUrl":{"type":"string","description":"선택 — linkUrl = 발급사 처방전 원문 링크 — 미연동 시 null","example":"https://edb.example.com/rx/9f3a2b1c"}}},"PrescriptionView":{"type":"object","description":"처방전(주문) 상세 — POST /api/v1/prescriptions 등록 응답, GET /api/v1/prescriptions/detail, 관리자 GET /api/v1/admin/prescriptions 목록/상세","properties":{"id":{"type":"integer","format":"int64","description":"id = 처방전(주문) PK — 상태 변경/관리자 수정 요청의 prescriptionId","example":101},"prescriptionSeq":{"type":"integer","format":"int32","description":"선택 — prescriptionSeq = 주문 번호 (order_no, 순번) — null 가능","example":1024},"status":{"type":"string","description":"status = 주문 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료","example":"02"},"statusName":{"type":"string","description":"statusName = 주문 상태 한글 라벨","example":"조제가능"},"receiveType":{"type":"string","description":"receiveType = 수령 방식 — onLine 택배배송 / offLine 방문수령","example":"onLine"},"unavailableReason":{"type":"string","description":"선택 — unavailableReason = 조제불가 사유 — 상태 03 일 때만","example":"재고 부족"},"prescriptionPrice":{"type":"number","description":"선택 — prescriptionPrice = 약제비 (원) — 조제가능(02) 처리 시 약사 입력","example":12500},"deliveryPrice":{"type":"number","description":"선택 — deliveryPrice = 배송비 (원) — offLine 은 0/null","example":3000},"totalPrice":{"type":"number","description":"선택 — totalPrice = 총 결제 금액 (원, 약제비 + 배송비)","example":15500},"medicineDirection":{"type":"string","description":"선택 — medicineDirection = 약사 복약 안내 (회원 노출)","example":"식후 30분에 1정씩 복용하세요."},"pharmacistMemo":{"type":"string","description":"선택 — pharmacistMemo = 약사 내부 메모 — 관리자 전용, 회원 응답에서는 null","example":"재고 확인 필요"},"qrValue":{"type":"string","description":"qrValue = 처방전 QR 원문 (또는 OCR 식별값)","example":"PRS_ENC:9f3a2b1c…"},"prescriptionImageUrl":{"type":"string","description":"선택 — prescriptionImageUrl = 처방전 이미지 URL (/uploads/... 경로, UPLOAD_URL_PREFIX 접두)","example":"/uploads/prescription/7/2026-09-11/3f9c1a2b__rx.jpg"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명 (주문 시점 스냅샷)","example":"약나루약국 남구점"},"pharmacyPhone":{"type":"string","description":"pharmacyPhone = 약국 전화번호 (스냅샷)","example":"051-123-4567"},"pharmacyAddress":{"type":"string","description":"pharmacyAddress = 약국 주소 (스냅샷)","example":"부산광역시 남구 수영로 200"},"memId":{"type":"string","description":"선택 — memId = 주문 회원 로그인 아이디 — 관리자 목록/상세에서만, 회원 응답은 null","example":"hong1234"},"memName":{"type":"string","description":"선택 — memName = 주문 회원 이름 — 관리자 목록/상세에서만","example":"홍길동"},"deliveryName":{"type":"string","description":"선택 — deliveryName = 수령인 이름 — onLine 배송지 스냅샷","example":"홍길동"},"deliveryPhone":{"type":"string","description":"선택 — deliveryPhone = 수령인 연락처 — onLine 배송지 스냅샷","example":"010-1234-5678"},"deliveryAddress":{"type":"string","description":"선택 — deliveryAddress = 배송 기본 주소 — onLine 배송지 스냅샷","example":"부산광역시 해운대구 센텀중앙로 79"},"deliveryDetailAddress":{"type":"string","description":"선택 — deliveryDetailAddress = 배송 상세 주소 (동/호수)","example":"101동 1203호"},"deliveryNumber":{"type":"string","description":"선택 — deliveryNumber = 택배 송장번호 — 배송중(06) 전환 시 약사 입력","example":6889012345678},"deliveryCompany":{"type":"string","description":"선택 — deliveryCompany = 택배사명 (CJ대한통운/우체국 등) — 배송중(06) 전환 시 약사 입력","example":"CJ대한통운"},"reqDate":{"type":"string","format":"date-time","description":"reqDate = 처방전 접수(주문) 일시 (ISO-8601)","example":"2026-09-11T09:30:00"},"readyAt":{"type":"string","format":"date-time","description":"선택 — readyAt = 조제가능(02) 진입 일시 (ISO-8601) — 미도달 시 null","example":"2026-09-11T09:45:00"},"paidAt":{"type":"string","format":"date-time","description":"선택 — paidAt = 결제완료(04) 진입 일시 (ISO-8601) — 미도달 시 null","example":"2026-09-11T10:00:00"},"preparedAt":{"type":"string","format":"date-time","description":"선택 — preparedAt = 조제완료(05) 진입 일시 (ISO-8601) — 방문수령만, 미도달 시 null","example":"2026-09-11T10:30:00"},"inTransitAt":{"type":"string","format":"date-time","description":"선택 — inTransitAt = 배송중(06) 진입 일시 (ISO-8601) — 택배배송만, 미도달 시 null","example":"2026-09-11T14:00:00"},"deliveredAt":{"type":"string","format":"date-time","description":"선택 — deliveredAt = 배송완료(07) 진입 일시 (ISO-8601) — 미도달 시 null","example":"2026-09-12T11:00:00"},"pickedUpAt":{"type":"string","format":"date-time","description":"선택 — pickedUpAt = 수령완료(010) 진입 일시 (ISO-8601) — 미도달 시 null","example":"2026-09-12T11:05:00"},"medicineList":{"type":"array","description":"medicineList = 처방 약품 목록","items":{"$ref":"#/components/schemas/MedicineView"}},"partnerInfo":{"$ref":"#/components/schemas/PartnerInfo","description":"선택 — partnerInfo = 처방전 발급 정보 (병원/의사/환자/진단/처방일) — null = 자가입력 또는 미연동"}}},"ApiResponseUploadImageResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/UploadImageResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"UploadImageResponse":{"type":"object","description":"처방전 이미지 업로드 응답 — POST /api/v1/prescriptions/upload-image","properties":{"storagePath":{"type":"string","description":"storagePath = 서버 저장 경로 — 처방전 등록 요청의 prescriptionImagePath / qrImagePath 로 전달","example":"C:/DEV/.../uploads/prescription/7/2026-09-11/3f9c1a2b__rx.jpg"},"fileName":{"type":"string","description":"fileName = 업로드 원본 파일명","example":"rx.jpg"},"size":{"type":"integer","format":"int64","description":"size = 파일 크기 (byte)","example":1048576}}},"ChangeStatusRequest":{"type":"object","description":"처방전 상태 변경 요청 — POST /api/v1/prescriptions/update-status (회원 취소/수령완료 등)","properties":{"prescriptionId":{"type":"integer","format":"int64","description":"prescriptionId = 대상 처방전(주문) PK — GET /api/v1/orders 의 prescriptionSeq","example":101},"status":{"type":"string","description":"status = 변경할 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료","example":"010","minLength":1},"unavailableReason":{"type":"string","description":"선택 — unavailableReason = 조제불가 사유 — status=03 일 때","example":"재고 부족"}},"required":["prescriptionId","status"]},"OcrMedicine":{"type":"object","description":"OCR 추출 약품 1건","properties":{"code":{"type":"string","description":"code = 약품 코드 (EDI 보험코드 9자리)","example":640007270},"name":{"type":"string","description":"선택 — name = 약품명 (인접 텍스트 기반 추정)","example":"타이레놀정500mg"}}},"OcrPrescriptionData":{"type":"object","description":"앱 CLOVA General OCR 파싱 결과 — 처방전 주요 필드 (파싱된 항목만, 전부 선택)","properties":{"issueNo":{"type":"string","description":"선택 — issueNo = 처방전 교부번호","example":"2026-0911-00042"},"patientName":{"type":"string","description":"선택 — patientName = 환자 성명","example":"홍길동"},"hospitalName":{"type":"string","description":"선택 — hospitalName = 의료기관 명칭","example":"부산대학교병원"},"doctorName":{"type":"string","description":"선택 — doctorName = 처방 의사 성명","example":"김의사"},"prescriptionDate":{"type":"string","description":"선택 — prescriptionDate = 교부일 (YYYY-MM-DD)","example":"2026-09-11"},"medicines":{"type":"array","description":"선택 — medicines = OCR 추출 약품 목록","items":{"$ref":"#/components/schemas/OcrMedicine"}}}},"QrCallbackRequest":{"type":"object","description":"처방전 QR/OCR 콜백 요청 — POST /api/v1/prescriptions/qr-callback (현재는 ocr 파싱 결과 전송, prsEnc 는 구 QR 경로)","properties":{"prsEnc":{"type":"string","description":"선택 — prsEnc = 처방전 QR 암호문 (구 EDB QR 방식) — 현재 미사용","example":"PRS_ENC:9f3a2b1c…"},"ocr":{"$ref":"#/components/schemas/OcrPrescriptionData","description":"선택 — ocr = 앱 CLOVA OCR 파싱 결과 — 현행 경로"}}},"ApiResponseQrCallbackResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/QrCallbackResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"QrCallbackResponse":{"type":"object","description":"처방전 QR/OCR 콜백 응답 — 인식 성공 시 medicineSeq 를 처방전 등록 요청에 전달","properties":{"success":{"type":"boolean","description":"success = 인식/저장 성공 여부","example":true},"medicineSeq":{"type":"integer","format":"int64","description":"선택 — medicineSeq = 생성된 발급정보 PK — 처방전 등록 요청의 medicineSeq, 실패 시 null","example":55},"linkUrl":{"type":"string","description":"선택 — linkUrl = 발급사 처방전 원문 링크 — 현재 null","example":null},"message":{"type":"string","description":"선택 — message = 실패 사유 — 성공 시 null","example":"처방전 인식 정보가 없습니다."}}},"ApiResponsePharmacistSignUpResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PharmacistSignUpResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PharmacistSignUpResponse":{"type":"object","description":"약사 회원가입 응답 — 생성된 약사 계정 + 자동 발급 약국 코드 + 상태(PENDING)","properties":{"adminUserId":{"type":"integer","format":"int64","description":"adminUserId = 생성된 약사 관리자 PK (admin_user.admin_id)","example":8},"pharmacyCode":{"type":"string","description":"pharmacyCode = 자동 발급된 약국 코드 (PH-### 형식, 순번 증가)","example":"PH-006"},"adminId":{"type":"string","description":"adminId = 약사 로그인 아이디","example":"pharmacist06"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명","example":"약나루약국 남구점"},"state":{"type":"string","description":"state = 계정 상태 — 가입 직후 항상 PENDING (SYSTEM_ADMIN 승인 전 로그인 차단)","example":"PENDING"}}},"CheckDeliveryRequest":{"type":"object","description":"비배송(산간/도서) 지역 확인 요청 — POST /api/v1/pharmacies/check-delivery","properties":{"zonecode":{"type":"string","description":"zonecode = 우편번호 (5자리) — 비배송 우편번호 목록과 대조","example":48058,"minLength":1},"roadname":{"type":"string","description":"선택 — roadname = 도로명 — 비배송 도로명 목록과 부분 일치 대조","example":"센텀중앙로"}},"required":["zonecode"]},"ApiResponseCheckDeliveryResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/CheckDeliveryResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"CheckDeliveryResponse":{"type":"object","description":"비배송 지역 확인 응답","properties":{"deliveryYn":{"type":"string","description":"deliveryYn = 배송 가능 여부 — Y 가능 / N 비배송 지역","example":"Y"},"reason":{"type":"string","description":"선택 — reason = 비배송 판정 사유 — deliveryYn=N 일 때만 (비배송 지역 (zipcode) / 비배송 지역 (도로명))","example":null}}},"SignUpRequest":{"type":"object","description":"회원가입 요청 — POST /api/v1/members/signup","properties":{"memId":{"type":"string","description":"memId = 로그인 아이디 (4~64자, 중복 불가 — POST /api/v1/members/check-id 로 사전 확인)","example":"hong1234","maxLength":64,"minLength":4},"memPass":{"type":"string","description":"memPass = 비밀번호 (8~64자)","example":"********","maxLength":64,"minLength":8},"memEmail":{"type":"string","description":"memEmail = 이메일 (중복 불가 — POST /api/v1/members/check-email 로 사전 확인)","example":"hong@example.com","minLength":1},"memName":{"type":"string","description":"memName = 회원 이름","example":"홍길동","minLength":1},"memBirth":{"type":"string","description":"선택 — memBirth = 생년월일 (YYYY-MM-DD)","example":"1960-05-20"},"memGender":{"type":"string","description":"선택 — memGender = 성별 코드 — 0 남성 / 1 여성","example":0},"memTel":{"type":"string","description":"선택 — memTel = 휴대폰 번호","example":"010-1234-5678"},"memDi":{"type":"string","description":"선택 — memDi = 본인인증(NICE) DI 값 — 중복 가입 차단 키, POST /api/v1/members/check-di 로 사전 확인","example":"MC0GCCqGSIb3DQIJAyEA3f9a…"},"memRecommend":{"type":"integer","format":"int64","description":"선택 — memRecommend = 추천인 회원 PK (97593712 − 추천인 코드) — 현재 서버에서 저장하지 않는 예약 필드","example":3}},"required":["memEmail","memId","memName","memPass"]},"ApiResponseTokenResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/TokenResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MemberInfo":{"type":"object","description":"회원 정보 — GET /api/v1/members/me 응답 및 로그인 응답의 myInfo","properties":{"id":{"type":"integer","format":"int64","description":"id = 회원 PK (member_info.member_id)","example":7},"memSeq":{"type":"integer","format":"int32","description":"memSeq = 구 시스템 회원 순번 — V28 이후 컬럼 제거, 항상 null (RN 호환용 잔존)","example":null},"memId":{"type":"string","description":"memId = 로그인 아이디","example":"hong1234"},"memEmail":{"type":"string","description":"memEmail = 이메일","example":"hong@example.com"},"memName":{"type":"string","description":"memName = 회원 이름","example":"홍길동"},"memBirth":{"type":"string","description":"선택 — memBirth = 생년월일 (YYYY-MM-DD) — null = 미입력","example":"1960-05-20"},"memGender":{"type":"string","description":"선택 — memGender = 성별 코드 — 0 남성 / 1 여성","example":0},"memTel":{"type":"string","description":"선택 — memTel = 휴대폰 번호","example":"010-1234-5678"},"memPush":{"type":"string","description":"memPush = 광고성 정보 수신동의 — Y / N (서비스 알림 발송과 무관)","example":"Y"},"memNotify":{"type":"string","description":"memNotify = 앱 [푸시 알림] 스위치 — Y 받음 / N 받지 않음","example":"Y"},"memState":{"type":"string","description":"memState = 회원 상태 — ACTIVE 정상 / DORMANT 휴면 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"ACTIVE"},"roles":{"type":"array","description":"roles = 권한 집합 — RN 회원은 USER 단일","example":["USER"],"items":{"type":"string"},"uniqueItems":true}}},"TokenResponse":{"type":"object","description":"회원 로그인/갱신 응답 — 액세스 토큰 + 내 정보","properties":{"tokenType":{"type":"string","description":"tokenType = 토큰 유형 — 항상 Bearer (Authorization: Bearer {accessToken})","example":"Bearer"},"accessToken":{"type":"string","description":"accessToken = JWT 액세스 토큰 — 회원 API 호출 시 Authorization 헤더에 사용","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJob25nMTIzNCIsInJvbGVzIjpbIlVTRVIiXX0.Q2fX…"},"refreshToken":{"type":"string","description":"refreshToken = 갱신 토큰 — POST /api/v1/auth/refresh 에 사용","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJob25nMTIzNCIsInR5cCI6InJlZnJlc2gifQ.7LmP…"},"expiresIn":{"type":"integer","format":"int64","description":"expiresIn = 액세스 토큰 만료까지 남은 시간 (초)","example":3600},"myInfo":{"$ref":"#/components/schemas/MemberInfo","description":"myInfo = 로그인한 회원 정보"}}},"ResetPasswordRequest":{"type":"object","description":"회원 비밀번호 찾기 요청 — POST /api/v1/members/password (아이디+이메일 일치 시 임시 비밀번호 메일 발송)","properties":{"memId":{"type":"string","description":"memId = 로그인 아이디","example":"hong1234","minLength":1},"memEmail":{"type":"string","description":"memEmail = 계정에 등록된 이메일 — 아이디와 일치해야 발송","example":"hong@example.com","minLength":1}},"required":["memEmail","memId"]},"UpdateProfileRequest":{"type":"object","description":"회원 프로필 수정 요청 — POST /api/v1/members/me/update (null 필드는 미변경)","properties":{"memEmail":{"type":"string","description":"선택 — memEmail = 이메일 — null = 미변경","example":"hong@example.com"},"memTel":{"type":"string","description":"선택 — memTel = 휴대폰 번호 — null = 미변경","example":"010-1234-5678"},"memZipcode":{"type":"string","description":"선택 — memZipcode = 우편번호 (5자리) — null = 미변경","example":48058},"memAddr1":{"type":"string","description":"선택 — memAddr1 = 기본 주소 — null = 미변경","example":"부산광역시 해운대구 센텀중앙로 79"},"memAddr2":{"type":"string","description":"선택 — memAddr2 = 상세 주소 — null = 미변경","example":"101동 1203호"}}},"ApiResponseMemberInfo":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/MemberInfo","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"SetPushAgreeRequest":{"type":"object","description":"푸시 수신 동의 변경 요청 — POST /api/v1/members/me/update-push","properties":{"memPush":{"type":"string","description":"memPush = 푸시 수신 동의 — Y 동의 / N 거부","example":"Y","minLength":1}},"required":["memPush"]},"ChangePasswordRequest":{"type":"object","description":"회원 비밀번호 변경 요청 — POST /api/v1/members/me/update-password","properties":{"oldPass":{"type":"string","description":"oldPass = 현재 비밀번호","example":"********","minLength":1},"newPass":{"type":"string","description":"newPass = 새 비밀번호 (8~64자)","example":"********","maxLength":64,"minLength":8}},"required":["newPass","oldPass"]},"SetNotifyRequest":{"type":"object","description":"알림 수신 설정 변경 요청 — POST /api/v1/members/me/update-notify","properties":{"memNotify":{"type":"string","description":"memNotify = 알림 받기 — Y 받음 / N 받지 않음","example":"Y","minLength":1,"pattern":"^[YNyn]$"}},"required":["memNotify"]},"FcmTokenRequest":{"type":"object","description":"FCM 토큰 등록 요청 — POST /api/v1/members/me/register-fcm","properties":{"fcmToken":{"type":"string","description":"fcmToken = Firebase Cloud Messaging 디바이스 토큰","example":"dXk9f3…:APA91bH…","minLength":1}},"required":["fcmToken"]},"CheckRecommendRequest":{"type":"object","description":"추천인 코드 확인 요청 — POST /api/v1/members/check-recommend","properties":{"code":{"type":"string","description":"code = 추천인 코드 (숫자) — 97593712 − 추천인 회원 PK 로 생성, 해당 회원 존재 시 valid=true","example":97593709,"minLength":1}},"required":["code"]},"ApiResponseMapStringBoolean":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"object","additionalProperties":{"type":"boolean"},"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"CheckIdRequest":{"type":"object","description":"아이디 중복 확인 요청 — POST /api/v1/members/check-id","properties":{"memId":{"type":"string","description":"memId = 확인할 로그인 아이디","example":"hong1234","minLength":1}},"required":["memId"]},"CheckEmailRequest":{"type":"object","description":"이메일 중복 확인 요청 — POST /api/v1/members/check-email","properties":{"memEmail":{"type":"string","description":"memEmail = 확인할 이메일","example":"hong@example.com","minLength":1}},"required":["memEmail"]},"CheckDiRequest":{"type":"object","description":"본인인증 DI 중복 확인 요청 — POST /api/v1/members/check-di (이미 가입된 DI 인지 확인)","properties":{"memDi":{"type":"string","description":"memDi = 본인인증(NICE) DI 값","example":"MC0GCCqGSIb3DQIJAyEA3f9a…","minLength":1}},"required":["memDi"]},"RejectRequest":{"type":"object","description":"자격 반려 요청 — POST /api/v1/admin/eligibility/reject (상태 I → R, 사유 회원 노출)","properties":{"eligibilityId":{"type":"integer","format":"int64","description":"eligibilityId = 반려 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id","example":21},"reason":{"type":"string","description":"선택 — reason = 반려 사유 — 회원 앱에 rejectDesc 로 노출","example":"서류 식별이 불가하여 재제출이 필요합니다."}},"required":["eligibilityId"]},"ApiResponseEligibilitySummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/EligibilitySummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"EligibilitySummary":{"type":"object","description":"약 배송 자격 신청 요약 — GET /api/v1/eligibility/latest 및 관리자 GET /api/v1/admin/eligibility 목록 항목","properties":{"id":{"type":"integer","format":"int64","description":"id = 자격 신청 PK — 관리자 승인/반려 요청의 eligibilityId","example":21},"memberId":{"type":"integer","format":"int64","description":"memberId = 신청 회원 PK (member_info.member_id)","example":7},"memberLoginId":{"type":"string","description":"선택 — memberLoginId = 신청 회원 로그인 아이디 — 관리자 목록에서만 채움","example":"hong1234"},"memberName":{"type":"string","description":"선택 — memberName = 신청 회원 이름 — 관리자 목록에서만 채움","example":"홍길동"},"state":{"type":"string","description":"state = 자격 상태 — I 심사중 / S 완료(배송 이용 가능) / R 반려(재신청 가능)","enum":["I","S","R"],"example":"I"},"documentTypes":{"type":"string","description":"documentTypes = 신청 자격 유형 코드 — ltc65plus 65세 이상 장기요양등급자 / disabled 장애인 / infectiousDisease 감염병 환자 / rareDisease 희귀질환자","example":"ltc65plus"},"rejectDesc":{"type":"string","description":"선택 — rejectDesc = 반려 사유 — state=R 일 때만, 그 외 null","example":"서류 식별이 불가하여 재제출이 필요합니다."},"documentCount":{"type":"integer","format":"int32","description":"documentCount = 첨부 서류 파일 수","example":2},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 신청 일시 (ISO-8601)","example":"2026-09-10T14:20:00"},"updatedAt":{"type":"string","format":"date-time","description":"updatedAt = 최종 변경 일시 (ISO-8601) — 승인/반려 시 갱신","example":"2026-09-11T09:30:00"}}},"ApiResponseEligibilityDetail":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/EligibilityDetail","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"EligibilityDetail":{"type":"object","description":"자격 신청 상세 — GET /api/v1/admin/eligibility/detail 및 POST /api/v1/eligibility/documents 응답 (요약 + 첨부 서류 목록)","properties":{"summary":{"$ref":"#/components/schemas/EligibilitySummary","description":"summary = 자격 신청 요약"},"documents":{"type":"array","description":"documents = 첨부 서류 목록","items":{"$ref":"#/components/schemas/EligibilityDocumentInfo"}}}},"EligibilityDocumentInfo":{"type":"object","description":"자격 첨부 서류 1건 — 자격 상세(documents) 항목","properties":{"id":{"type":"integer","format":"int64","description":"id = 첨부 파일 PK (eligibility_file.file_id)","example":33},"fileName":{"type":"string","description":"fileName = 업로드 원본 파일명","example":"장기요양인정서.jpg"},"fileSize":{"type":"integer","format":"int64","description":"fileSize = 파일 크기 (byte)","example":512000},"mimeType":{"type":"string","description":"mimeType = 파일 MIME 타입","example":"image/jpeg"},"fileUrl":{"type":"string","description":"fileUrl = 조회 URL (/uploads/... 경로, UPLOAD_URL_PREFIX 접두)","example":"/uploads/eligibility/7/2026-09-10/9a1b2c3d__doc.jpg"}}},"ApproveRequest":{"type":"object","description":"자격 승인 요청 — POST /api/v1/admin/eligibility/approve (상태 I → S)","properties":{"eligibilityId":{"type":"integer","format":"int64","description":"eligibilityId = 승인 대상 자격 신청 PK — GET /api/v1/admin/eligibility 목록의 id","example":21}},"required":["eligibilityId"]},"QnaWriteRequest":{"type":"object","description":"1:1 문의 작성 요청 — POST /api/v1/bbs/qnas (회원)","properties":{"categoryId":{"type":"integer","format":"int64","description":"선택 — categoryId = 문의 카테고리 PK — GET /api/v1/bbs/qna-form 의 카테고리 id","example":3},"question":{"type":"string","description":"question = 문의 내용 (2~4000자)","example":"배송이 며칠 걸리나요?","maxLength":4000,"minLength":2}},"required":["question"]},"ApiResponseQnaView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/QnaView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"QnaView":{"type":"object","description":"1:1 문의(QnA) 게시글 — GET /api/v1/bbs/qnas 목록 항목, 관리자 GET /api/v1/admin/bbs/qnas 및 /qnas/detail 응답","properties":{"id":{"type":"integer","format":"int64","description":"id = 문의글 PK — 관리자 답변 요청(POST /api/v1/admin/bbs/qnas/answer)의 postId","example":42},"boardType":{"type":"string","description":"boardType = 게시판 종류 슬러그 — 항상 qna","example":"qna"},"categoryId":{"type":"integer","format":"int64","description":"선택 — categoryId = 문의 카테고리 PK — GET /api/v1/bbs/qna-form 의 카테고리 id","example":3},"categoryName":{"type":"string","description":"선택 — categoryName = 문의 카테고리명","example":"주문/배송"},"memberId":{"type":"integer","format":"int64","description":"memberId = 작성 회원 PK (member_info.member_id)","example":7},"question":{"type":"string","description":"question = 문의 내용","example":"배송이 며칠 걸리나요?"},"answer":{"type":"string","description":"선택 — answer = 관리자 답변 내용 — 미답변 시 null","example":"결제 완료 후 보통 1~2일 내 도착합니다."},"status":{"type":"string","description":"status = 답변 상태 한글 라벨 — 답변대기 / 답변완료","example":"답변완료"},"qDate":{"type":"string","format":"date-time","description":"qDate = 문의 등록 일시 (ISO-8601)","example":"2026-09-10T14:20:00"},"answerDate":{"type":"string","format":"date-time","description":"선택 — answerDate = 답변 일시 (ISO-8601) — 미답변 시 null","example":"2026-09-11T09:30:00"}}},"RefreshRequest":{"type":"object","description":"회원 토큰 갱신 요청 — POST /api/v1/auth/refresh","properties":{"refreshToken":{"type":"string","description":"refreshToken = 갱신 토큰 — POST /api/v1/auth/login 응답의 refreshToken","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJob25nMTIzNCIsInR5cCI6InJlZnJlc2gifQ.7LmP…","minLength":1}},"required":["refreshToken"]},"LoginRequest":{"type":"object","description":"회원(RN 앱) 로그인 요청 — POST /api/v1/auth/login","properties":{"memId":{"type":"string","description":"memId = 회원 로그인 아이디 — 회원가입(POST /api/v1/members/signup) 시 지정","example":"hong1234","minLength":1},"memPass":{"type":"string","description":"memPass = 비밀번호 (평문, TLS 구간 전송)","example":"********","minLength":1}},"required":["memId","memPass"]},"UpdateRequest":{"type":"object","description":"앱 구동 설정 갱신 요청 — POST /api/v1/app/setting/update (관리자, null 필드는 미변경)","properties":{"platform":{"type":"string","description":"platform = 대상 플랫폼 — android / ios","example":"android","minLength":1},"up_bool":{"type":"string","description":"선택 — up_bool = 강제 업데이트 사용 여부 — yes / no, null = 미변경","example":"no"},"up_build":{"type":"integer","format":"int32","description":"선택 — up_build = 강제 업데이트 기준 빌드 번호 — null = 미변경","example":12},"up_img":{"type":"string","description":"선택 — up_img = 업데이트 안내 이미지 URL — null = 미변경","example":"https://cdn.yaknaru.co.kr/app/update.png"},"up_img_width":{"type":"integer","format":"int32","description":"선택 — up_img_width = 업데이트 안내 이미지 가로 (px) — null = 미변경","example":720},"up_img_height":{"type":"integer","format":"int32","description":"선택 — up_img_height = 업데이트 안내 이미지 세로 (px) — null = 미변경","example":1280},"agree_bool":{"type":"string","description":"선택 — agree_bool = 약관 재동의 강제 여부 — yes / no, null = 미변경","example":"no"},"agree_no":{"type":"integer","format":"int32","description":"선택 — agree_no = 재동의가 필요한 약관 버전 번호 — null = 미변경","example":2},"popup_bool":{"type":"string","description":"선택 — popup_bool = 팝업 노출 여부 — yes / no, null = 미변경","example":"no"},"popup_img":{"type":"string","description":"선택 — popup_img = 팝업 이미지 URL — null = 미변경","example":"https://cdn.yaknaru.co.kr/app/popup.png"},"server_bool":{"type":"string","description":"선택 — server_bool = 서버 점검 중 여부 — yes / no, null = 미변경","example":"no"},"server_img":{"type":"string","description":"선택 — server_img = 점검 안내 이미지 URL — null = 미변경","example":"https://cdn.yaknaru.co.kr/app/maint.png"},"server_img_width":{"type":"integer","format":"int32","description":"선택 — server_img_width = 점검 안내 이미지 가로 (px) — null = 미변경","example":720},"server_img_height":{"type":"integer","format":"int32","description":"선택 — server_img_height = 점검 안내 이미지 세로 (px) — null = 미변경","example":1280},"ocr_bool":{"type":"string","description":"선택 — ocr_bool = 처방전 OCR 사용 여부 — yes / no, null = 미변경","example":"no"}},"required":["platform"]},"ApiResponseAppSettingView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AppSettingView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"AppSettingView":{"type":"object","description":"앱 구동 설정 — GET /api/v1/app/setting?platform= 응답 (RN Loading 화면 호환 snake_case 키)","properties":{"platform":{"type":"string","description":"platform = 대상 플랫폼 — android / ios","example":"android"},"up_bool":{"type":"string","description":"up_bool = 강제 업데이트 사용 여부 — yes / no (yes 이고 up_build > 단말 빌드면 업데이트 안내)","example":"no"},"up_build":{"type":"integer","format":"int32","description":"선택 — up_build = 강제 업데이트 기준 빌드 번호 — 단말 빌드가 이보다 작으면 업데이트","example":12},"up_img":{"type":"string","description":"선택 — up_img = 업데이트 안내 이미지 URL","example":"https://cdn.yaknaru.co.kr/app/update.png"},"up_img_width":{"type":"integer","format":"int32","description":"선택 — up_img_width = 업데이트 안내 이미지 가로 (px)","example":720},"up_img_height":{"type":"integer","format":"int32","description":"선택 — up_img_height = 업데이트 안내 이미지 세로 (px)","example":1280},"agree_bool":{"type":"string","description":"agree_bool = 약관 재동의 강제 여부 — yes / no","example":"no"},"agree_no":{"type":"integer","format":"int32","description":"선택 — agree_no = 재동의가 필요한 약관 버전 번호","example":2},"popup_bool":{"type":"string","description":"popup_bool = 광고/공지 팝업 노출 여부 — yes / no","example":"no"},"popup_img":{"type":"string","description":"선택 — popup_img = 팝업 이미지 URL","example":"https://cdn.yaknaru.co.kr/app/popup.png"},"server_bool":{"type":"string","description":"server_bool = 서버 점검 중 여부 — yes / no (yes 면 앱 진입 차단)","example":"no"},"server_img":{"type":"string","description":"선택 — server_img = 서버 점검 안내 이미지 URL","example":"https://cdn.yaknaru.co.kr/app/maint.png"},"server_img_width":{"type":"integer","format":"int32","description":"선택 — server_img_width = 점검 안내 이미지 가로 (px)","example":720},"server_img_height":{"type":"integer","format":"int32","description":"선택 — server_img_height = 점검 안내 이미지 세로 (px)","example":1280},"ocr_bool":{"type":"string","description":"ocr_bool = 처방전 OCR 사용 여부 — yes / no. no 면 앱이 OCR 을 호출하지 않는다(과금 0). OCR 이 꺼지면 주민등록번호 마스킹·발급정보 자동입력·흐린 사진 차단도 함께 동작하지 않는다.","example":"no"}}},"SettingUpdateRequest":{"type":"object","description":"건강샵 운영 설정 변경 요청 — POST /api/v1/admin/shop/settings/update (null 필드는 미변경)","properties":{"deliveryFee":{"type":"integer","format":"int32","description":"선택 — deliveryFee = 기본 배송비 (원) — null = 미변경","example":3000},"freeThreshold":{"type":"integer","format":"int32","description":"선택 — freeThreshold = 무료 배송 기준 주문 금액 (원) — null = 미변경","example":30000}}},"ApiResponseSettingView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/SettingView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"SettingView":{"type":"object","description":"건강샵 운영 설정 (배송비 정책) — GET /api/v1/shop/settings, 관리자 GET /api/v1/admin/shop/settings 응답","properties":{"deliveryFee":{"type":"integer","format":"int32","description":"deliveryFee = 기본 배송비 (원)","example":3000},"freeThreshold":{"type":"integer","format":"int32","description":"freeThreshold = 무료 배송 기준 주문 금액 (원) — 상품 합계가 이상이면 배송비 0","example":30000}}},"ProductUpdateRequest":{"type":"object","description":"상품 부분 수정 요청 — POST /api/v1/admin/shop/products/update (null 필드는 미변경)","properties":{"productCode":{"type":"string","description":"productCode = 대상 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식)","example":"HP-001","minLength":1},"category":{"type":"string","description":"선택 — category = 상품 카테고리명 — null = 미변경","example":"비타민"},"emoji":{"type":"string","description":"선택 — emoji = 카테고리 대표 이모지 — null = 미변경","example":"🍊"},"name":{"type":"string","description":"선택 — name = 상품명 — null = 미변경","example":"멀티비타민 미네랄 90정"},"brand":{"type":"string","description":"선택 — brand = 브랜드명 — null = 미변경","example":"약나루 헬스"},"brief":{"type":"string","description":"선택 — brief = 한 줄 소개 — null = 미변경","example":"하루 1정으로 챙기는 12종 비타민 + 8종 미네랄"},"price":{"type":"integer","format":"int32","description":"선택 — price = 판매가 (원) — null = 미변경","example":24900},"originalPrice":{"type":"integer","format":"int32","description":"선택 — originalPrice = 할인 전 정가 (원) — null = 미변경","example":32000},"badge":{"type":"string","description":"선택 — badge = 뱃지 — BEST / NEW, null = 미변경","example":"BEST"},"visible":{"type":"boolean","description":"선택 — visible = 앱 노출 여부 — null = 미변경","example":true},"functionality":{"type":"string","description":"선택 — functionality = 기능성 내용 — null = 미변경","example":"비타민 A·C·D·E 등 12종 비타민 보충"},"intake":{"type":"string","description":"선택 — intake = 섭취 방법 — null = 미변경","example":"1일 1회, 1회 1정을 물과 함께 섭취"},"caution":{"type":"string","description":"선택 — caution = 섭취 시 주의사항 — null = 미변경","example":"특정 질환이 있거나 의약품 복용 시 전문가와 상담 후 섭취하세요."},"image":{"type":"string","description":"선택 — image = 대표 이미지 (URL 또는 data URI) — null = 미변경","example":"https://cdn.yaknaru.co.kr/shop/HP-001.png"},"detailImages":{"type":"array","description":"선택 — detailImages = 상세 이미지 목록 — null = 미변경","example":["https://cdn.yaknaru.co.kr/shop/HP-001_1.png"],"items":{"type":"string"}}},"required":["productCode"]},"ApiResponseProductView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/ProductView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ProductView":{"type":"object","description":"건강샵 상품 — GET /api/v1/shop/products, 관리자 GET /api/v1/admin/shop/products 항목 (앱 HealthProduct 모델과 동일)","properties":{"id":{"type":"string","description":"id = 상품 코드 (HP-001 형식) — 주문 항목의 productId, 관리자 수정/삭제의 productCode","example":"HP-001"},"category":{"type":"string","description":"category = 상품 카테고리명 (자유 문자열)","example":"비타민"},"emoji":{"type":"string","description":"선택 — emoji = 카테고리 대표 이모지 (이미지 없을 때 표시)","example":"🍊"},"name":{"type":"string","description":"name = 상품명","example":"멀티비타민 미네랄 90정"},"brand":{"type":"string","description":"선택 — brand = 브랜드명","example":"약나루 헬스"},"brief":{"type":"string","description":"선택 — brief = 한 줄 소개","example":"하루 1정으로 챙기는 12종 비타민 + 8종 미네랄"},"price":{"type":"integer","format":"int32","description":"price = 판매가 (원)","example":24900},"originalPrice":{"type":"integer","format":"int32","description":"선택 — originalPrice = 할인 전 정가 (원) — null = 할인 없음","example":32000},"badge":{"type":"string","description":"선택 — badge = 뱃지 — BEST / NEW, null = 없음","example":"BEST"},"visible":{"type":"boolean","description":"visible = 앱 노출 여부 — false 면 관리자에서만 조회","example":true},"functionality":{"type":"string","description":"선택 — functionality = 기능성 내용 (줄바꿈 구분)","example":"비타민 A·C·D·E 등 12종 비타민 보충\n아연·셀레늄 등 8종 미네랄 보충"},"intake":{"type":"string","description":"선택 — intake = 섭취 방법","example":"1일 1회, 1회 1정을 물과 함께 섭취"},"caution":{"type":"string","description":"선택 — caution = 섭취 시 주의사항","example":"특정 질환이 있거나 의약품 복용 시 전문가와 상담 후 섭취하세요."},"image":{"type":"string","description":"선택 — image = 대표 이미지 (URL 또는 data URI)","example":"https://cdn.yaknaru.co.kr/shop/HP-001.png"},"detailImages":{"type":"array","description":"detailImages = 상세 이미지 목록 (URL 또는 data URI)","example":["https://cdn.yaknaru.co.kr/shop/HP-001_1.png"],"items":{"type":"string"}}}},"ProductDeleteRequest":{"type":"object","description":"상품 삭제 요청 — POST /api/v1/admin/shop/products/delete","properties":{"productCode":{"type":"string","description":"productCode = 삭제 대상 상품 코드 — GET /api/v1/shop/products 의 id (HP-001 형식)","example":"HP-001","minLength":1}},"required":["productCode"]},"ProductCreateRequest":{"type":"object","description":"상품 등록 요청 — POST /api/v1/admin/shop/products/create (상품 코드 HP-### 자동 채번)","properties":{"category":{"type":"string","description":"category = 상품 카테고리명","example":"비타민","minLength":1},"emoji":{"type":"string","description":"선택 — emoji = 카테고리 대표 이모지","example":"🍊"},"name":{"type":"string","description":"name = 상품명","example":"멀티비타민 미네랄 90정","minLength":1},"brand":{"type":"string","description":"선택 — brand = 브랜드명","example":"약나루 헬스"},"brief":{"type":"string","description":"선택 — brief = 한 줄 소개","example":"하루 1정으로 챙기는 12종 비타민 + 8종 미네랄"},"price":{"type":"integer","format":"int32","description":"price = 판매가 (원)","example":24900},"originalPrice":{"type":"integer","format":"int32","description":"선택 — originalPrice = 할인 전 정가 (원) — null = 할인 없음","example":32000},"badge":{"type":"string","description":"선택 — badge = 뱃지 — BEST / NEW","example":"BEST"},"visible":{"type":"boolean","description":"선택 — visible = 앱 노출 여부 — null = true","example":true},"functionality":{"type":"string","description":"선택 — functionality = 기능성 내용 (줄바꿈 구분)","example":"비타민 A·C·D·E 등 12종 비타민 보충"},"intake":{"type":"string","description":"선택 — intake = 섭취 방법","example":"1일 1회, 1회 1정을 물과 함께 섭취"},"caution":{"type":"string","description":"선택 — caution = 섭취 시 주의사항","example":"특정 질환이 있거나 의약품 복용 시 전문가와 상담 후 섭취하세요."},"image":{"type":"string","description":"선택 — image = 대표 이미지 (URL 또는 data URI)","example":"https://cdn.yaknaru.co.kr/shop/HP-001.png"},"detailImages":{"type":"array","description":"선택 — detailImages = 상세 이미지 목록 (URL 또는 data URI)","example":["https://cdn.yaknaru.co.kr/shop/HP-001_1.png"],"items":{"type":"string"}}},"required":["category","name","price"]},"StatusUpdateRequest":{"type":"object","description":"건강샵 주문 상태 변경 요청 — POST /api/v1/admin/shop/orders/update-status","properties":{"orderNo":{"type":"string","description":"orderNo = 대상 주문번호 — GET /api/v1/admin/shop/orders 의 id (SO-YYYYMMDD-### 형식)","example":"SO-20260911-001","minLength":1},"status":{"type":"string","description":"status = 변경할 상태 코드 — PAID 결제 완료 / SHIPPING 배송 중 / DELIVERED 배송 완료","example":"SHIPPING","minLength":1}},"required":["orderNo","status"]},"RoleMenuUpdateRequest":{"type":"object","description":"권한별 메뉴 저장 요청 — POST /api/v1/admin/roles/menus/update. 보낸 목록으로 통째로 교체한다.","properties":{"roleCode":{"type":"string","description":"roleCode = 권한 코드","example":"PHARMACY_ADMIN","minLength":1},"menuCodes":{"type":"array","description":"menuCodes = 허용할 메뉴코드 목록 — 빈 배열이면 모든 메뉴 차단","example":["prescriptionMgt","myProfile"],"items":{"type":"string"}}},"required":["menuCodes","roleCode"]},"ApiResponseRoleMenuView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/RoleMenuView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"RoleMenuView":{"type":"object","description":"권한별 메뉴 설정 — GET /api/v1/admin/roles/menus?roleCode= 응답","properties":{"roleCode":{"type":"string","description":"roleCode = 권한 코드","example":"PHARMACY_ADMIN"},"roleName":{"type":"string","description":"roleName = 권한명 — 코드그룹 admin_role 의 코드명","example":"약사"},"menuCodes":{"type":"array","description":"menuCodes = 이 권한에 허용된 메뉴코드 목록","example":["prescriptionMgt","orderMgt"],"items":{"type":"string"}}}},"AdminUpdatePrescriptionRequest":{"type":"object","description":"관리자 처방전 부분 수정 요청 — POST /api/v1/admin/prescriptions/update (null 필드는 미변경)","properties":{"prescriptionId":{"type":"integer","format":"int64","description":"prescriptionId = 대상 처방전(주문) PK — GET /api/v1/admin/prescriptions 목록의 id","example":101},"status":{"type":"string","description":"선택 — status = 변경할 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료, null = 미변경","example":"06"},"prescriptionPrice":{"type":"number","description":"선택 — prescriptionPrice = 약제비 (원) — null = 미변경","example":12500},"deliveryPrice":{"type":"number","description":"선택 — deliveryPrice = 배송비 (원) — null = 미변경","example":3000},"medicineDirection":{"type":"string","description":"선택 — medicineDirection = 약사 복약 안내 (회원 노출) — null = 미변경","example":"식후 30분에 1정씩 복용하세요."},"deliveryNumber":{"type":"string","description":"선택 — deliveryNumber = 택배 송장번호 — 배송중(06) 전환 시 입력, null = 미변경","example":6889012345678},"deliveryCompany":{"type":"string","description":"선택 — deliveryCompany = 택배사명 (CJ대한통운/우체국 등) — 배송중(06) 전환 시 입력, null = 미변경","example":"CJ대한통운"},"unavailableReason":{"type":"string","description":"선택 — unavailableReason = 조제불가 사유 — status=03 일 때, null = 미변경","example":"재고 부족"},"pharmacistMemo":{"type":"string","description":"선택 — pharmacistMemo = 약사 내부 메모 (회원 미노출) — null = 미변경","example":"재고 확인 필요"}},"required":["prescriptionId"]},"AdminMedicineItem":{"type":"object","description":"관리자 수정용 약품 1건 — MedicineView 의 drgCd/drgNm/dosage/daysTotal 대응","properties":{"code":{"type":"string","description":"code = 약품 코드 (EDI 보험코드 9자리)","example":640007270},"name":{"type":"string","description":"선택 — name = 약품명","example":"타이레놀정500mg"},"dosage":{"type":"string","description":"선택 — dosage = 1회 투약량","example":1},"daysTotal":{"type":"string","description":"선택 — daysTotal = 총 투약 일수","example":3}}},"AdminUpdatePartnerInfoRequest":{"type":"object","description":"관리자 처방전 발급정보 수정 요청 — POST /api/v1/admin/prescriptions/update-partner-info (OCR 오인식 보정, 전송값 그대로 저장·빈 문자열은 null)","properties":{"prescriptionId":{"type":"integer","format":"int64","description":"prescriptionId = 대상 처방전(주문) PK — GET /api/v1/admin/prescriptions 목록의 id","example":101},"hospitalName":{"type":"string","description":"선택 — hospitalName = 의료기관 명칭","example":"부산대학교병원"},"hospitalPhone":{"type":"string","description":"선택 — hospitalPhone = 의료기관 전화번호","example":"051-240-7000"},"doctorName":{"type":"string","description":"선택 — doctorName = 처방 의사 성명","example":"김의사"},"doctorLicenseNo":{"type":"string","description":"선택 — doctorLicenseNo = 의사 면허번호","example":98765},"patientName":{"type":"string","description":"선택 — patientName = 환자 성명","example":"홍길동"},"departmentCode":{"type":"string","description":"선택 — departmentCode = 진료과목 코드","example":"01"},"diagnosisCode1":{"type":"string","description":"선택 — diagnosisCode1 = 주상병 코드 (KCD)","example":"J06.9"},"diagnosisCode2":{"type":"string","description":"선택 — diagnosisCode2 = 부상병 코드 (KCD)","example":"R50.9"},"prescriptionDate":{"type":"string","description":"선택 — prescriptionDate = 처방전 교부일 (YYYY-MM-DD)","example":"2026-09-11"},"useDays":{"type":"string","description":"선택 — useDays = 처방전 사용기간 (일)","example":3},"medicines":{"type":"array","description":"선택 — medicines = 약품 목록 — null = 미변경, 리스트 전송 시 기존 약품 전체 교체","items":{"$ref":"#/components/schemas/AdminMedicineItem"}}},"required":["prescriptionId"]},"AdminPharmacyUpdateRequest":{"type":"object","description":"약국 부분 수정 요청 — POST /api/v1/admin/pharmacies/update (null 필드는 미변경)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001","minLength":1},"pharmacyName":{"type":"string","description":"선택 — pharmacyName = 약국명 — null = 미변경","example":"약나루약국 남구점"},"pharmacyPhone":{"type":"string","description":"선택 — pharmacyPhone = 약국 대표 전화 — null = 미변경","example":"051-123-4567"},"zipcode":{"type":"string","description":"선택 — zipcode = 우편번호 (5자리) — null = 미변경","example":48434},"address":{"type":"string","description":"선택 — address = 약국 기본 주소 — null = 미변경","example":"부산광역시 남구 수영로 200"},"detailAddress":{"type":"string","description":"선택 — detailAddress = 약국 상세 주소 — null = 미변경","example":"1층 101호"},"gpsLat":{"type":"number","description":"선택 — gpsLat = 위도 (WGS84) — null = 미변경","example":35.1367},"gpsLon":{"type":"number","description":"선택 — gpsLon = 경도 (WGS84) — null = 미변경","example":129.0862},"deliveryYn":{"type":"string","description":"선택 — deliveryYn = 택배 배송 지원 여부 — Y / N, null = 미변경","example":"Y"},"alarmPhone":{"type":"string","description":"선택 — alarmPhone = 처방전 접수 알림 수신 전화번호 — null = 미변경","example":"010-9876-5432"},"pharmacistName":{"type":"string","description":"선택 — pharmacistName = 약사 이름 — null = 미변경","example":"홍길동"},"pharmacistPhone":{"type":"string","description":"선택 — pharmacistPhone = 약사 전화번호 — null = 미변경","example":"010-1234-5678"},"licenseNum":{"type":"string","description":"선택 — licenseNum = 약사 면허번호 — null = 미변경","example":12345},"businessNum":{"type":"string","description":"선택 — businessNum = 사업자등록번호 — null = 미변경","example":"123-45-67890"},"accountBankName":{"type":"string","description":"선택 — accountBankName = 정산 계좌 은행명 — null = 미변경","example":"부산은행"},"accountBankNumber":{"type":"string","description":"선택 — accountBankNumber = 정산 계좌번호 — null = 미변경","example":"101-2345-6789-01"},"accountOwner":{"type":"string","description":"선택 — accountOwner = 정산 계좌 예금주 — null = 미변경","example":"홍길동"},"openTimeMon":{"type":"string","description":"선택 — openTimeMon = 월요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~18:00"},"openTimeTue":{"type":"string","description":"선택 — openTimeTue = 화요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~18:00"},"openTimeWed":{"type":"string","description":"선택 — openTimeWed = 수요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~18:00"},"openTimeThu":{"type":"string","description":"선택 — openTimeThu = 목요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~18:00"},"openTimeFri":{"type":"string","description":"선택 — openTimeFri = 금요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~18:00"},"openTimeSat":{"type":"string","description":"선택 — openTimeSat = 토요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"09:00~13:00"},"openTimeSun":{"type":"string","description":"선택 — openTimeSun = 일요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미변경","example":"휴무"},"pharmacyCharge":{"type":"number","description":"선택 — pharmacyCharge = 플랫폼 중개 수수료율 (%) — null = 미변경","example":3.5},"reviewMemo":{"type":"string","description":"선택 — reviewMemo = SYSTEM_ADMIN 검토 메모 — null = 미변경","example":"사업자등록증 확인 완료"}},"required":["pharmacyCode"]},"ApiResponsePharmacyView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PharmacyView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PharmacyView":{"type":"object","description":"약국 정보 — GET /api/v1/pharmacies 목록 항목, /detail 응답 및 관리자 생성/수정 응답","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 약국 코드 (PH-001 형식) — 처방전 등록·관리자 약국 API 의 식별자","example":"PH-001"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명","example":"약나루약국 남구점"},"pharmacyPhone":{"type":"string","description":"선택 — pharmacyPhone = 약국 대표 전화","example":"051-123-4567"},"zipcode":{"type":"string","description":"선택 — zipcode = 우편번호 (5자리)","example":48434},"pharmacyAddress":{"type":"string","description":"pharmacyAddress = 약국 기본 주소","example":"부산광역시 남구 수영로 200"},"pharmacyDetailAddress":{"type":"string","description":"선택 — pharmacyDetailAddress = 약국 상세 주소","example":"1층 101호"},"gpsLat":{"type":"number","description":"선택 — gpsLat = 위도 (WGS84)","example":35.1367},"gpsLon":{"type":"number","description":"선택 — gpsLon = 경도 (WGS84)","example":129.0862},"effectiveStatus":{"type":"string","description":"effectiveStatus = 실효 영업 상태 — 영업중 / 준비중 (현재 시각과 요일별 영업시간으로 자동 계산, 영업시간 미설정 시 영업중)","example":"영업중"},"deliveryYn":{"type":"string","description":"deliveryYn = 택배 배송 지원 여부 — Y / N","example":"Y"},"alarmPhone":{"type":"string","description":"선택 — alarmPhone = 처방전 접수 알림 수신 전화번호","example":"010-9876-5432"},"pharmacistName":{"type":"string","description":"선택 — pharmacistName = 약사 이름","example":"홍길동"},"pharmacistPhone":{"type":"string","description":"선택 — pharmacistPhone = 약사 전화번호","example":"010-1234-5678"},"licenseNum":{"type":"string","description":"선택 — licenseNum = 약사 면허번호","example":12345},"businessNum":{"type":"string","description":"선택 — businessNum = 사업자등록번호","example":"123-45-67890"},"accountBankName":{"type":"string","description":"선택 — accountBankName = 정산 계좌 은행명","example":"부산은행"},"accountBankNumber":{"type":"string","description":"선택 — accountBankNumber = 정산 계좌번호","example":"101-2345-6789-01"},"accountOwner":{"type":"string","description":"선택 — accountOwner = 정산 계좌 예금주","example":"홍길동"},"openTimeMon":{"type":"string","description":"선택 — openTimeMon = 월요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~18:00"},"openTimeTue":{"type":"string","description":"선택 — openTimeTue = 화요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~18:00"},"openTimeWed":{"type":"string","description":"선택 — openTimeWed = 수요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~18:00"},"openTimeThu":{"type":"string","description":"선택 — openTimeThu = 목요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~18:00"},"openTimeFri":{"type":"string","description":"선택 — openTimeFri = 금요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~18:00"},"openTimeSat":{"type":"string","description":"선택 — openTimeSat = 토요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"09:00~13:00"},"openTimeSun":{"type":"string","description":"선택 — openTimeSun = 일요일 영업시간 — HH:mm~HH:mm 또는 휴무, null = 미설정","example":"휴무"},"pharmacyCharge":{"type":"number","description":"선택 — pharmacyCharge = 플랫폼 중개 수수료율 (%) — SYSTEM_ADMIN 설정, null = 미설정","example":3.5},"reviewMemo":{"type":"string","description":"선택 — reviewMemo = SYSTEM_ADMIN 검토 메모 — null/공백 = 메모 없음","example":"사업자등록증 확인 완료"},"lastReviewedAt":{"type":"string","format":"date-time","description":"선택 — lastReviewedAt = 마지막 검토 일시 (ISO-8601) — 검토메모 저장/승인/반려 시 갱신","example":"2026-09-11T09:30:00"},"pendingAdminCount":{"type":"integer","format":"int32","description":"선택 — pendingAdminCount = 매핑된 약사 중 PENDING(검토대기) 수 — 관리자 목록에서만 채움, 0 = 정상","example":0},"distance":{"type":"integer","format":"int64","description":"선택 — distance = 검색 위치로부터의 거리 (m) — 위치 기반 검색(lat/lon 전달) 시에만, 그 외 null","example":850}}},"AdminPharmacyReviewMemoRequest":{"type":"object","description":"약국 검토 메모 저장 요청 — POST /api/v1/admin/pharmacies/update-review-memo (SYSTEM_ADMIN, lastReviewedAt 갱신)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001","minLength":1},"reviewMemo":{"type":"string","description":"선택 — reviewMemo = 검토 메모 — null/공백 = 메모 삭제","example":"사업자등록증 확인 완료"}},"required":["pharmacyCode"]},"AdminPharmacyChargeRequest":{"type":"object","description":"약국 중개 수수료율 저장 요청 — POST /api/v1/admin/pharmacies/update-charge (SYSTEM_ADMIN)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 대상 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001","minLength":1},"pharmacyCharge":{"type":"number","description":"선택 — pharmacyCharge = 플랫폼 중개 수수료율 (%) — null = 미설정으로 저장","example":3.5}},"required":["pharmacyCode"]},"AdminPharmacyRejectRequest":{"type":"object","description":"약사 회원가입 반려 요청 — POST /api/v1/admin/pharmacies/reject (매핑 약사 PENDING → SUSPENDED, 사유 메일 통보)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 대상 약국 코드 — 약사 회원가입 응답의 pharmacyCode (PH-001 형식)","example":"PH-006","minLength":1},"reviewMemo":{"type":"string","description":"reviewMemo = 반려 사유 (필수) — 약사에게 통보","example":"사업자등록증 이미지가 식별되지 않습니다.","minLength":1}},"required":["pharmacyCode","reviewMemo"]},"AdminPharmacyReviewResponse":{"type":"object","description":"약사 회원가입 승인/반려 결과 응답","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 처리된 약국 코드 (PH-001 형식)","example":"PH-006"},"affectedAdminCount":{"type":"integer","format":"int32","description":"affectedAdminCount = 상태가 변경된 약사 계정 수","example":1},"result":{"type":"string","description":"result = 처리 결과 — APPROVED 승인 / REJECTED 반려","example":"APPROVED"}}},"ApiResponseAdminPharmacyReviewResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AdminPharmacyReviewResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"AdminPharmacyCreateRequest":{"type":"object","description":"약국 등록 요청 — POST /api/v1/admin/pharmacies/create (SYSTEM_ADMIN)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 약국 코드 (PH-### 형식, 중복 불가)","example":"PH-006","minLength":1},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명","example":"약나루약국 남구점","minLength":1},"pharmacyPhone":{"type":"string","description":"선택 — pharmacyPhone = 약국 대표 전화","example":"051-123-4567"},"zipcode":{"type":"string","description":"선택 — zipcode = 우편번호 (5자리)","example":48434},"address":{"type":"string","description":"선택 — address = 약국 기본 주소","example":"부산광역시 남구 수영로 200"},"detailAddress":{"type":"string","description":"선택 — detailAddress = 약국 상세 주소","example":"1층 101호"},"gpsLat":{"type":"number","description":"선택 — gpsLat = 위도 (WGS84)","example":35.1367},"gpsLon":{"type":"number","description":"선택 — gpsLon = 경도 (WGS84)","example":129.0862},"deliveryYn":{"type":"string","description":"선택 — deliveryYn = 택배 배송 지원 여부 — Y / N, null = N","example":"Y"},"openTimeMon":{"type":"string","description":"선택 — openTimeMon = 월요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~18:00"},"openTimeTue":{"type":"string","description":"선택 — openTimeTue = 화요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~18:00"},"openTimeWed":{"type":"string","description":"선택 — openTimeWed = 수요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~18:00"},"openTimeThu":{"type":"string","description":"선택 — openTimeThu = 목요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~18:00"},"openTimeFri":{"type":"string","description":"선택 — openTimeFri = 금요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~18:00"},"openTimeSat":{"type":"string","description":"선택 — openTimeSat = 토요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"09:00~13:00"},"openTimeSun":{"type":"string","description":"선택 — openTimeSun = 일요일 영업시간 — HH:mm~HH:mm 또는 휴무","example":"휴무"}},"required":["pharmacyCode","pharmacyName"]},"AdminPharmacyApproveRequest":{"type":"object","description":"약사 회원가입 승인 요청 — POST /api/v1/admin/pharmacies/approve (매핑 약사 PENDING → ACTIVE)","properties":{"pharmacyCode":{"type":"string","description":"pharmacyCode = 대상 약국 코드 — 약사 회원가입 응답의 pharmacyCode (PH-001 형식)","example":"PH-006","minLength":1},"reviewMemo":{"type":"string","description":"선택 — reviewMemo = 승인 시 남길 검토 메모","example":"서류 확인 완료, 승인"}},"required":["pharmacyCode"]},"MenuUpdateRequest":{"type":"object","description":"메뉴 수정 요청 — POST /api/v1/admin/menus/update. 메뉴코드는 바꿀 수 없고 보낸 항목만 바뀐다.","properties":{"menuId":{"type":"integer","format":"int64","description":"menuId = 수정할 메뉴 PK","example":10},"parentCode":{"type":"string","description":"선택 — parentCode = 상위 메뉴코드 — 빈 문자열이면 최상위로","example":"sysMgt"},"menuName":{"type":"string","description":"선택 — menuName = 메뉴명","example":"코드관리","maxLength":100,"minLength":0},"menuPath":{"type":"string","description":"선택 — menuPath = 이동 경로","example":"/sysMgt/codeMgt","maxLength":200,"minLength":0},"menuIcon":{"type":"string","description":"선택 — menuIcon = antd 아이콘 이름","example":"SettingOutlined","maxLength":50,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 같은 레벨 안 순서","example":40},"useYn":{"type":"string","description":"선택 — useYn = 사용 여부 (Y/N)","example":"Y","pattern":"^[YNyn]$"}},"required":["menuId"]},"ApiResponseMenuView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/MenuView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MenuView":{"type":"object","description":"메뉴 — GET /api/v1/admin/menus 트리 항목 (children 에 하위 메뉴)","properties":{"menuId":{"type":"integer","format":"int64","description":"menuId = 메뉴 PK — 수정/삭제 요청의 menuId","example":10},"parentCode":{"type":"string","description":"선택 — parentCode = 상위 메뉴코드 — 최상위는 null","example":"sysMgt"},"menuCode":{"type":"string","description":"menuCode = 메뉴코드 — 관리자웹 라우트 key 와 1:1","example":"codeMgt"},"menuName":{"type":"string","description":"menuName = 메뉴명","example":"코드관리"},"menuPath":{"type":"string","description":"선택 — menuPath = 이동 경로 — 자식이 있는 상위 메뉴는 null","example":"/sysMgt/codeMgt"},"menuIcon":{"type":"string","description":"선택 — menuIcon = antd 아이콘 이름","example":"SettingOutlined"},"menuLevel":{"type":"integer","format":"int32","description":"menuLevel = 깊이 — 0 최상위 / 1 하위","example":1},"sortNo":{"type":"integer","format":"int32","description":"sortNo = 같은 레벨 안 순서","example":40},"useYn":{"type":"string","description":"useYn = 사용 여부","example":"Y"},"children":{"type":"array","description":"children = 하위 메뉴 목록 — 없으면 빈 배열","items":{"description":"메뉴 — GET /api/v1/admin/menus 트리 항목 (children 에 하위 메뉴)"}}}},"MenuDeleteRequest":{"type":"object","description":"메뉴 삭제 요청 — POST /api/v1/admin/menus/delete. 하위 메뉴가 있으면 삭제 불가.","properties":{"menuId":{"type":"integer","format":"int64","description":"menuId = 삭제할 메뉴 PK","example":23}},"required":["menuId"]},"MenuCreateRequest":{"type":"object","description":"메뉴 등록 요청 — POST /api/v1/admin/menus/create. 화면이 없는 메뉴코드를 넣으면 클릭해도 빈 화면이 된다.","properties":{"parentCode":{"type":"string","description":"선택 — parentCode = 상위 메뉴코드 — 최상위면 비움","example":"sysMgt"},"menuCode":{"type":"string","description":"menuCode = 메뉴코드 — 관리자웹 라우트 key","example":"codeMgt","maxLength":50,"minLength":0,"pattern":"^[a-zA-Z0-9_]+$"},"menuName":{"type":"string","description":"menuName = 메뉴명","example":"코드관리","maxLength":100,"minLength":0},"menuPath":{"type":"string","description":"선택 — menuPath = 이동 경로","example":"/sysMgt/codeMgt","maxLength":200,"minLength":0},"menuIcon":{"type":"string","description":"선택 — menuIcon = antd 아이콘 이름","example":"SettingOutlined","maxLength":50,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 같은 레벨 안 순서","example":40}},"required":["menuCode","menuName"]},"AdminMemberStateRequest":{"type":"object","description":"회원 상태 변경 요청 — POST /api/v1/admin/members/update-state (SYSTEM_ADMIN)","properties":{"memberId":{"type":"integer","format":"int64","description":"memberId = 대상 회원 PK — GET /api/v1/admin/members 목록의 id","example":7},"state":{"type":"string","description":"state = 변경할 회원 상태 — ACTIVE 정상 / DORMANT 휴면 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"SUSPENDED","minLength":1}},"required":["memberId","state"]},"AdminMemberSummary":{"type":"object","description":"회원 요약 — 관리자 GET /api/v1/admin/members 목록 항목 및 /detail 응답","properties":{"id":{"type":"integer","format":"int64","description":"id = 회원 PK — 상태 변경 요청(POST /api/v1/admin/members/update-state)의 memberId","example":7},"memSeq":{"type":"integer","format":"int32","description":"memSeq = 구 시스템 회원 순번 — V28 이후 컬럼 제거, 항상 null","example":null},"memId":{"type":"string","description":"memId = 로그인 아이디","example":"hong1234"},"memName":{"type":"string","description":"memName = 회원 이름","example":"홍길동"},"memEmail":{"type":"string","description":"memEmail = 이메일","example":"hong@example.com"},"memTel":{"type":"string","description":"선택 — memTel = 휴대폰 번호","example":"010-1234-5678"},"memState":{"type":"string","description":"memState = 회원 상태 — ACTIVE 정상 / DORMANT 휴면 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"ACTIVE"},"roles":{"type":"array","description":"roles = 권한 집합 — RN 회원은 USER 단일","example":["USER"],"items":{"type":"string"},"uniqueItems":true},"createdAt":{"type":"string","description":"createdAt = 가입 일시 (ISO-8601 문자열)","example":"2026-05-01T10:00:00"}}},"ApiResponseAdminMemberSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AdminMemberSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"UpdateMeRequest":{"type":"object","description":"관리자 내 프로필 부분 수정 요청 — POST /api/v1/admin/me/update (null 필드는 미변경, adminId/roles/state 는 본인 변경 불가)","properties":{"adminName":{"type":"string","description":"선택 — adminName = 관리자 이름 (40자 이하) — null = 미변경","example":"홍길동","maxLength":40,"minLength":0},"adminEmail":{"type":"string","description":"선택 — adminEmail = 관리자 이메일 (120자 이하) — null = 미변경","example":"pharm01@yaknaru.local","maxLength":120,"minLength":0},"adminTel":{"type":"string","description":"선택 — adminTel = 전화번호 (20자 이하) — null = 미변경","example":"010-1234-5678","maxLength":20,"minLength":0},"adminBirth":{"type":"string","format":"date","description":"선택 — adminBirth = 약사 생년월일 (YYYY-MM-DD) — null = 미변경","example":"1985-03-15"}}},"ApiResponseMeInfo":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/MeInfo","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MeInfo":{"type":"object","description":"관리자 내 정보 — GET /api/v1/admin/me 응답","properties":{"id":{"type":"integer","format":"int64","description":"id = 관리자 PK (admin_user.admin_id)","example":3},"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디","example":"pharmacist01"},"adminName":{"type":"string","description":"adminName = 관리자 이름","example":"홍길동"},"adminEmail":{"type":"string","description":"adminEmail = 관리자 이메일","example":"pharm01@yaknaru.local"},"adminTel":{"type":"string","description":"adminTel = 관리자 전화번호","example":"010-1234-5678"},"adminBirth":{"type":"string","format":"date","description":"선택 — adminBirth = 약사 생년월일 (YYYY-MM-DD) — PHARMACY_ADMIN 만 의미, null = 미설정","example":"1985-03-15"},"adminState":{"type":"string","description":"adminState = 계정 상태 — PENDING 검토대기 / ACTIVE 정상 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"ACTIVE"},"roles":{"type":"array","description":"roles = 권한 집합 — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자","example":["PHARMACY_ADMIN"],"items":{"type":"string"},"uniqueItems":true},"lastLoginAt":{"type":"string","format":"date-time","description":"lastLoginAt = 마지막 로그인 일시 (ISO-8601) — null = 로그인 이력 없음","example":"2026-09-11T09:30:00"},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 계정 생성 일시 (ISO-8601)","example":"2026-05-01T10:00:00"}}},"ApiResponseUploadResult":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/UploadResult","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"UploadResult":{"type":"object","description":"약품 마스터 업로드 결과 (전체 교체)","properties":{"loaded":{"type":"integer","format":"int32","description":"loaded = 적재한 행 수 — 제품코드가 9자리 숫자인 행","example":21998},"skipped":{"type":"integer","format":"int32","description":"skipped = 건너뛴 행 수 — 제품코드 형식이 아니거나 빈 행","example":0},"total":{"type":"integer","format":"int64","description":"total = 적재 후 마스터 전체 건수","example":21998}}},"CodeItemUpdateRequest":{"type":"object","description":"코드 수정 요청 — POST /api/v1/admin/codes/update. 코드값은 바꿀 수 없고 보낸 항목만 바뀐다.","properties":{"codeId":{"type":"integer","format":"int64","description":"codeId = 수정할 코드 PK","example":3},"codeName":{"type":"string","description":"선택 — codeName = 코드명","example":"접수대기","maxLength":100,"minLength":0},"codeDesc":{"type":"string","description":"선택 — codeDesc = 설명","example":"약국 확인 전","maxLength":300,"minLength":0},"extraValue":{"type":"string","description":"선택 — extraValue = 부가값","example":"blue","maxLength":100,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 정렬 순번","example":10},"useYn":{"type":"string","description":"선택 — useYn = 사용 여부 (Y/N)","example":"Y","pattern":"^[YNyn]$"}},"required":["codeId"]},"ApiResponseCodeItemView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/CodeItemView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"CodeItemView":{"type":"object","description":"공통코드 — GET /api/v1/admin/codes?groupCode= 목록 항목","properties":{"codeId":{"type":"integer","format":"int64","description":"codeId = 코드 PK — 수정/삭제 요청의 codeId","example":3},"groupCode":{"type":"string","description":"groupCode = 소속 그룹코드","example":"prescription_status"},"codeValue":{"type":"string","description":"codeValue = 코드값 — 백엔드 enum·DB 저장값과 1:1, 수정 불가","example":"01"},"codeName":{"type":"string","description":"codeName = 코드명 — 화면에 보이는 이름","example":"발송"},"codeDesc":{"type":"string","description":"선택 — codeDesc = 설명","example":"약국이 아직 확인하지 않은 상태"},"extraValue":{"type":"string","description":"선택 — extraValue = 부가값 — 목록 태그 색상 등 표시 보조값","example":"blue"},"sortNo":{"type":"integer","format":"int32","description":"sortNo = 정렬 순번","example":10},"useYn":{"type":"string","description":"useYn = 사용 여부 — N 이면 검색 선택 목록에서 숨김","example":"Y"}}},"CodeGroupUpdateRequest":{"type":"object","description":"코드 그룹 수정 요청 — POST /api/v1/admin/codes/groups/update. 보낸 항목만 바뀐다.","properties":{"groupCode":{"type":"string","description":"groupCode = 수정할 그룹코드","example":"carrier","minLength":1},"groupName":{"type":"string","description":"선택 — groupName = 그룹명","example":"택배사","maxLength":100,"minLength":0},"groupDesc":{"type":"string","description":"선택 — groupDesc = 설명","example":"송장 등록 시 선택","maxLength":300,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 정렬 순번","example":30},"useYn":{"type":"string","description":"선택 — useYn = 사용 여부 (Y/N)","example":"Y","pattern":"^[YNyn]$"}},"required":["groupCode"]},"ApiResponseCodeGroupView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/CodeGroupView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"CodeGroupView":{"type":"object","description":"코드 그룹 — GET /api/v1/admin/codes/groups 목록 항목","properties":{"groupCode":{"type":"string","description":"groupCode = 그룹코드 — 코드 목록 조회·수정 요청의 키","example":"prescription_status"},"groupName":{"type":"string","description":"groupName = 그룹명","example":"처방전 상태"},"groupDesc":{"type":"string","description":"선택 — groupDesc = 설명","example":"처방전·주문 진행 상태"},"systemYn":{"type":"string","description":"systemYn = 시스템 그룹 여부 — Y 면 그룹 삭제 불가(코드명 수정은 가능)","example":"Y"},"sortNo":{"type":"integer","format":"int32","description":"sortNo = 정렬 순번","example":10},"useYn":{"type":"string","description":"useYn = 사용 여부","example":"Y"},"codeCount":{"type":"integer","format":"int64","description":"codeCount = 그룹에 속한 코드 수","example":10}}},"CodeGroupDeleteRequest":{"type":"object","description":"코드 그룹 삭제 요청 — POST /api/v1/admin/codes/groups/delete. 시스템 그룹과 코드가 남은 그룹은 삭제 불가.","properties":{"groupCode":{"type":"string","description":"groupCode = 삭제할 그룹코드","example":"carrier","minLength":1}},"required":["groupCode"]},"CodeGroupCreateRequest":{"type":"object","description":"코드 그룹 등록 요청 — POST /api/v1/admin/codes/groups/create","properties":{"groupCode":{"type":"string","description":"groupCode = 그룹코드 — 영문 소문자·숫자·밑줄만","example":"carrier","maxLength":50,"minLength":0,"pattern":"^[a-zA-Z0-9_]+$"},"groupName":{"type":"string","description":"groupName = 그룹명","example":"택배사","maxLength":100,"minLength":0},"groupDesc":{"type":"string","description":"선택 — groupDesc = 설명","example":"송장 등록 시 선택하는 택배사","maxLength":300,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 정렬 순번","example":30}},"required":["groupCode","groupName"]},"CodeItemDeleteRequest":{"type":"object","description":"코드 삭제 요청 — POST /api/v1/admin/codes/delete. 시스템 그룹의 코드는 삭제 대신 사용여부 N 을 쓴다.","properties":{"codeId":{"type":"integer","format":"int64","description":"codeId = 삭제할 코드 PK","example":42}},"required":["codeId"]},"CodeItemCreateRequest":{"type":"object","description":"코드 등록 요청 — POST /api/v1/admin/codes/create","properties":{"groupCode":{"type":"string","description":"groupCode = 소속 그룹코드","example":"carrier","minLength":1},"codeValue":{"type":"string","description":"codeValue = 코드값 — 같은 그룹 안에서 중복 불가","example":"cu","maxLength":50,"minLength":0},"codeName":{"type":"string","description":"codeName = 코드명","example":"CU편의점택배","maxLength":100,"minLength":0},"codeDesc":{"type":"string","description":"선택 — codeDesc = 설명","example":"편의점 접수 택배","maxLength":300,"minLength":0},"extraValue":{"type":"string","description":"선택 — extraValue = 부가값 (태그 색상 등)","example":"green","maxLength":100,"minLength":0},"sortNo":{"type":"integer","format":"int32","description":"선택 — sortNo = 정렬 순번","example":60}},"required":["codeName","codeValue","groupCode"]},"AdminCategoryCreateRequest":{"type":"object","description":"게시판 카테고리 생성 요청 — POST /api/v1/admin/bbs/{board}-categories/create (board = faq / qna 는 path)","properties":{"name":{"type":"string","description":"name = 카테고리명","example":"배송/결제","minLength":1},"sort":{"type":"integer","format":"int32","description":"선택 — sort = 정렬 순서 (오름차순) — null = 기본값","example":1}},"required":["name"]},"ApiResponseCategoryView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/CategoryView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"CategoryView":{"type":"object","description":"게시판 카테고리 — GET /api/v1/bbs/faq-categories, /qna-form, 관리자 GET /api/v1/admin/bbs/{board}-categories 항목","properties":{"id":{"type":"integer","format":"int64","description":"id = 카테고리 PK — 게시글 작성/수정의 categoryId, 관리자 카테고리 수정/삭제의 categoryId","example":2},"boardType":{"type":"string","description":"boardType = 소속 게시판 슬러그 — faq / qna","example":"faq"},"name":{"type":"string","description":"name = 카테고리명","example":"배송/결제"},"sort":{"type":"integer","format":"int32","description":"sort = 정렬 순서 (오름차순)","example":1}}},"AdminQnaAnswerRequest":{"type":"object","description":"1:1 문의 관리자 답변 요청 — POST /api/v1/admin/bbs/qnas/answer (답변 저장 시 상태 답변완료)","properties":{"postId":{"type":"integer","format":"int64","description":"postId = 답변 대상 문의글 PK — GET /api/v1/admin/bbs/qnas 목록의 id","example":42},"answer":{"type":"string","description":"answer = 답변 내용","example":"결제 완료 후 보통 1~2일 내 도착합니다.","minLength":1}},"required":["answer","postId"]},"AdminPostCreateRequest":{"type":"object","description":"공지/FAQ 작성 요청 — POST /api/v1/admin/bbs/notices, /faqs","properties":{"subject":{"type":"string","description":"subject = 제목","example":"추석 연휴 배송 안내","minLength":1},"contents":{"type":"string","description":"contents = 본문 (HTML/텍스트)","example":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다.","minLength":1},"categoryId":{"type":"integer","format":"int64","description":"선택 — categoryId = 카테고리 PK — GET /api/v1/admin/bbs/faq-categories 의 id, FAQ 는 필수 / 공지는 null","example":2}},"required":["contents","subject"]},"ApiResponsePostView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PostView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PostView":{"type":"object","description":"공지/FAQ 게시글 — GET /api/v1/bbs/notices, /faqs 목록 항목 및 /notices/detail 응답","properties":{"id":{"type":"integer","format":"int64","description":"id = 게시글 PK — 관리자 수정/삭제 요청의 postId, GET /api/v1/bbs/notices/detail?id= 의 id","example":15},"bbsSeq":{"type":"integer","format":"int32","description":"bbsSeq = 구 시스템 게시글 순번 — V28 이후 컬럼 제거, 항상 null (RN 호환용 잔존)","example":null},"boardType":{"type":"string","description":"boardType = 게시판 종류 슬러그 — notice 공지 / faq 자주묻는질문 / qna 문의","example":"notice"},"categoryId":{"type":"integer","format":"int64","description":"선택 — categoryId = 카테고리 PK — FAQ 만 사용, 공지는 null","example":2},"categoryName":{"type":"string","description":"선택 — categoryName = 카테고리명 — FAQ 만 사용, 공지는 null","example":"배송/결제"},"subject":{"type":"string","description":"subject = 제목","example":"추석 연휴 배송 안내"},"contents":{"type":"string","description":"contents = 본문 (HTML/텍스트)","example":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다."},"viewCount":{"type":"integer","format":"int32","description":"viewCount = 조회수","example":128},"regDate":{"type":"string","format":"date-time","description":"regDate = 등록 일시 (ISO-8601)","example":"2026-09-11T09:30:00"}}},"AdminPostUpdateRequest":{"type":"object","description":"공지/FAQ 부분 수정 요청 — POST /api/v1/admin/bbs/notices/update, /faqs/update (null 필드는 미변경)","properties":{"postId":{"type":"integer","format":"int64","description":"postId = 수정 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id","example":15},"subject":{"type":"string","description":"선택 — subject = 제목 — null = 미변경","example":"추석 연휴 배송 안내"},"contents":{"type":"string","description":"선택 — contents = 본문 — null = 미변경","example":"추석 연휴 기간(10/3~10/6) 동안 택배 배송이 지연될 수 있습니다."},"categoryId":{"type":"integer","format":"int64","description":"선택 — categoryId = 카테고리 PK (FAQ) — null = 미변경","example":2}},"required":["postId"]},"AdminPostDeleteRequest":{"type":"object","description":"공지/FAQ 삭제 요청 — POST /api/v1/admin/bbs/notices/delete, /faqs/delete","properties":{"postId":{"type":"integer","format":"int64","description":"postId = 삭제 대상 게시글 PK — GET /api/v1/bbs/notices, /faqs 목록의 id","example":15}},"required":["postId"]},"AdminCategoryUpdateRequest":{"type":"object","description":"게시판 카테고리 부분 수정 요청 — POST /api/v1/admin/bbs/categories/update (null 필드는 미변경)","properties":{"categoryId":{"type":"integer","format":"int64","description":"categoryId = 수정 대상 카테고리 PK — GET /api/v1/admin/bbs/{board}-categories 의 id","example":2},"name":{"type":"string","description":"선택 — name = 카테고리명 — null = 미변경","example":"배송/결제"},"sort":{"type":"integer","format":"int32","description":"선택 — sort = 정렬 순서 — null = 미변경","example":1},"active":{"type":"boolean","description":"선택 — active = 활성 여부 (false 면 목록에서 숨김) — null = 미변경","example":true}},"required":["categoryId"]},"AdminCategoryDeleteRequest":{"type":"object","description":"게시판 카테고리 삭제(비활성) 요청 — POST /api/v1/admin/bbs/categories/delete","properties":{"categoryId":{"type":"integer","format":"int64","description":"categoryId = 삭제 대상 카테고리 PK — GET /api/v1/admin/bbs/{board}-categories 의 id","example":2}},"required":["categoryId"]},"AdminResetPasswordRequest":{"type":"object","description":"관리자 비밀번호 찾기 요청 — POST /api/v1/admin/auth/reset-password (아이디+이메일 일치 시 임시 비밀번호 메일 발송)","properties":{"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디","example":"pharmacist01","minLength":1},"adminEmail":{"type":"string","description":"adminEmail = 계정에 등록된 이메일 — 아이디와 일치해야 임시 비밀번호 발송","example":"pharm01@yaknaru.local","minLength":1}},"required":["adminEmail","adminId"]},"AdminRefreshRequest":{"type":"object","description":"관리자 토큰 갱신 요청 — POST /api/v1/admin/auth/refresh","properties":{"refreshToken":{"type":"string","description":"refreshToken = 갱신 토큰 — POST /api/v1/admin/auth/login 응답의 refreshToken","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwaGFybWFjaXN0MDEiLCJ0eXAiOiJyZWZyZXNoIn0.9qZk…","minLength":1}},"required":["refreshToken"]},"AdminInfo":{"type":"object","description":"관리자 요약 정보 — 로그인 응답(adminInfo)에 포함","properties":{"id":{"type":"integer","format":"int64","description":"id = 관리자 PK (admin_user.admin_id) — 관리자 계정 관리 API 의 adminId 로 사용","example":3},"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디","example":"pharmacist01"},"adminName":{"type":"string","description":"adminName = 관리자 이름","example":"홍길동"},"adminEmail":{"type":"string","description":"adminEmail = 관리자 이메일","example":"pharm01@yaknaru.local"},"adminTel":{"type":"string","description":"adminTel = 관리자 전화번호","example":"010-1234-5678"},"adminState":{"type":"string","description":"adminState = 계정 상태 — PENDING 검토대기(로그인 차단) / ACTIVE 정상 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"ACTIVE"},"roles":{"type":"array","description":"roles = 권한 집합 — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자","example":["PHARMACY_ADMIN"],"items":{"type":"string"},"uniqueItems":true}}},"AdminTokenResponse":{"type":"object","description":"관리자 로그인/갱신 응답 — 액세스 토큰 + 관리자 정보","properties":{"tokenType":{"type":"string","description":"tokenType = 토큰 유형 — 항상 Bearer (Authorization: Bearer {accessToken})","example":"Bearer"},"accessToken":{"type":"string","description":"accessToken = JWT 액세스 토큰 — 관리자 API 호출 시 Authorization 헤더에 사용","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwaGFybWFjaXN0MDEiLCJyb2xlcyI6WyJQSEFSTUFDWV9BRE1JTiJdfQ.Kt3x…"},"refreshToken":{"type":"string","description":"refreshToken = 갱신 토큰 — POST /api/v1/admin/auth/refresh 에 사용","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwaGFybWFjaXN0MDEiLCJ0eXAiOiJyZWZyZXNoIn0.9qZk…"},"expiresIn":{"type":"integer","format":"int64","description":"expiresIn = 액세스 토큰 만료까지 남은 시간 (초)","example":3600},"adminInfo":{"$ref":"#/components/schemas/AdminInfo","description":"adminInfo = 로그인한 관리자 요약 정보"}}},"ApiResponseAdminTokenResponse":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AdminTokenResponse","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"AdminLoginRequest":{"type":"object","description":"관리자(약사/시스템 운영자) 로그인 요청 — POST /api/v1/admin/auth/login","properties":{"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디 — 약사 회원가입(POST /api/v1/pharmacist/signup) 또는 SYSTEM_ADMIN 등록 시 지정","example":"pharmacist01","minLength":1},"adminPass":{"type":"string","description":"adminPass = 비밀번호 (평문, TLS 구간 전송)","example":"********","minLength":1}},"required":["adminId","adminPass"]},"AdminUserSummary":{"type":"object","description":"관리자 계정 요약/상세 — GET /api/v1/admin/admin-users 목록 행 및 /detail 응답 (pharmacies 는 상세에서만 채움)","properties":{"id":{"type":"integer","format":"int64","description":"id = 관리자 PK (admin_user.admin_id) — 수정/비밀번호 초기화/약국 매핑 요청의 adminId","example":3},"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디","example":"pharmacist01"},"adminName":{"type":"string","description":"adminName = 관리자 이름","example":"홍길동"},"adminEmail":{"type":"string","description":"adminEmail = 관리자 이메일","example":"pharm01@yaknaru.local"},"adminTel":{"type":"string","description":"adminTel = 관리자 전화번호","example":"010-1234-5678"},"adminBirth":{"type":"string","format":"date","description":"선택 — adminBirth = 약사 생년월일 (YYYY-MM-DD) — PHARMACY_ADMIN 만 의미, null 가능","example":"1985-03-15"},"adminState":{"type":"string","description":"adminState = 계정 상태 — PENDING 검토대기(로그인 차단) / ACTIVE 정상 / SUSPENDED 정지 / WITHDRAWN 탈퇴","example":"ACTIVE"},"roles":{"type":"array","description":"roles = 권한 집합 — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자","example":["PHARMACY_ADMIN"],"items":{"type":"string"},"uniqueItems":true},"pharmacies":{"type":"array","description":"pharmacies = 매핑된 약국 목록 — 단건 상세에서만 채움, 목록 검색에서는 빈 배열","items":{"$ref":"#/components/schemas/PharmacyMappingItem"}},"lastLoginAt":{"type":"string","format":"date-time","description":"lastLoginAt = 마지막 로그인 일시 (ISO-8601) — null = 로그인 이력 없음","example":"2026-09-11T09:30:00"},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 계정 생성 일시 (ISO-8601)","example":"2026-05-01T10:00:00"}}},"ApiResponseAdminUserSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AdminUserSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PharmacyMappingItem":{"type":"object","description":"관리자-약국 매핑 1건 — 관리자 상세(GET /api/v1/admin/admin-users/detail) 의 pharmacies 항목","properties":{"pharmacyId":{"type":"integer","format":"int64","description":"pharmacyId = 약국 PK (pharmacy.pharmacy_id) — 매핑 해제(POST /api/v1/admin/admin-users/pharmacies/remove) 의 pharmacyId","example":1},"pharmacyCode":{"type":"string","description":"pharmacyCode = 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명","example":"약나루약국 남구점"},"documentCount":{"type":"integer","format":"int32","description":"선택 — documentCount = 약국 첨부 서류 수 — 단건 상세에서만 채움, null = 미조회","example":2}}},"ResetPasswordByAdminRequest":{"type":"object","description":"관리자 비밀번호 초기화 요청 — POST /api/v1/admin/admin-users/reset-password (SYSTEM_ADMIN 이 타 계정 비밀번호 재설정)","properties":{"adminId":{"type":"integer","format":"int64","description":"adminId = 대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id","example":3},"newPassword":{"type":"string","description":"newPassword = 새 비밀번호 (6~64자)","example":"********","maxLength":64,"minLength":6}},"required":["adminId","newPassword"]},"PharmacyMappingRemoveRequest":{"type":"object","description":"관리자-약국 매핑 해제 요청 — POST /api/v1/admin/admin-users/pharmacies/remove","properties":{"adminId":{"type":"integer","format":"int64","description":"adminId = 대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id","example":3},"pharmacyId":{"type":"integer","format":"int64","description":"pharmacyId = 해제할 약국 PK — 관리자 상세(/detail) pharmacies 항목의 pharmacyId","example":1}},"required":["adminId","pharmacyId"]},"ApiResponseListPharmacyMappingItem":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/PharmacyMappingItem"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PharmacyMappingRequest":{"type":"object","description":"관리자-약국 매핑 추가 요청 — POST /api/v1/admin/admin-users/pharmacies/add","properties":{"adminId":{"type":"integer","format":"int64","description":"adminId = 대상 관리자 PK — GET /api/v1/admin/admin-users 목록의 id","example":3},"pharmacyCode":{"type":"string","description":"pharmacyCode = 매핑할 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001","minLength":1}},"required":["adminId","pharmacyCode"]},"CreateRequest":{"type":"object","description":"관리자 계정 생성 요청 — POST /api/v1/admin/admin-users/create (SYSTEM_ADMIN 전용)","properties":{"adminId":{"type":"string","description":"adminId = 관리자 로그인 아이디 (3~64자, 중복 불가)","example":"pharmacist06","maxLength":64,"minLength":3},"password":{"type":"string","description":"password = 초기 비밀번호 (6~64자)","example":"********","maxLength":64,"minLength":6},"adminName":{"type":"string","description":"adminName = 관리자 이름 (40자 이하)","example":"홍길동","maxLength":40,"minLength":0},"adminEmail":{"type":"string","description":"선택 — adminEmail = 관리자 이메일 (120자 이하)","example":"pharm06@yaknaru.local","maxLength":120,"minLength":0},"adminTel":{"type":"string","description":"선택 — adminTel = 전화번호 (20자 이하)","example":"010-1234-5678","maxLength":20,"minLength":0},"roles":{"type":"array","description":"roles = 권한 집합 (1개 이상) — PHARMACY_ADMIN 약사 / SYSTEM_ADMIN 시스템 운영자","example":["PHARMACY_ADMIN"],"items":{"type":"string","enum":["PHARMACY_ADMIN","SYSTEM_ADMIN"]},"minItems":1,"uniqueItems":true},"pharmacyCodes":{"type":"array","description":"선택 — pharmacyCodes = 등록 시 초기 매핑할 약국 코드 목록 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식), PHARMACY_ADMIN 일 때만 의미","example":["PH-001"],"items":{"type":"string"}}},"required":["adminId","adminName","password","roles"]},"AddressView":{"type":"object","description":"배송지 1건 — GET /api/v1/addresses 목록 항목 (회원 본인 배송지)","properties":{"deliveryAddressSeq":{"type":"integer","format":"int64","description":"deliveryAddressSeq = 배송지 PK — 수정/삭제 요청의 addressId 로 사용","example":12},"deliveryAddressName":{"type":"string","description":"deliveryAddressName = 받는 분 이름","example":"홍길동"},"deliveryAddressPhone":{"type":"string","description":"deliveryAddressPhone = 받는 분 연락처 — 숫자/하이픈","example":"010-1234-5678"},"deliveryAddressZipcode":{"type":"string","description":"deliveryAddressZipcode = 우편번호 (5자리)","example":48058},"deliveryAddress":{"type":"string","description":"deliveryAddress = 기본 주소 (도로명/지번)","example":"부산광역시 해운대구 센텀중앙로 79"},"deliveryDetailAddress":{"type":"string","description":"deliveryDetailAddress = 상세 주소 (동/호수)","example":"101동 1203호"},"roadName":{"type":"string","description":"roadName = 도로명 — 비배송 지역 판정(POST /api/v1/pharmacies/check-delivery)에 사용","example":"센텀중앙로"},"isDefault":{"type":"boolean","description":"isDefault = 기본 배송지 여부 — 회원당 1건만 true","example":true}}},"ApiResponseAddressView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AddressView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"DeleteRequest":{"type":"object","description":"배송지 삭제 요청 — POST /api/v1/addresses/delete","properties":{"addressId":{"type":"integer","format":"int64","description":"addressId = 삭제 대상 배송지 PK — GET /api/v1/addresses 의 deliveryAddressSeq","example":12}},"required":["addressId"]},"ApiResponseListProductView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/ProductView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseListOrderView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/OrderView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePageMessageInfo":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageMessageInfo","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MessageInfo":{"type":"object","description":"알림함 메시지 1건 — GET /api/v1/push/messages 목록 항목","properties":{"id":{"type":"integer","format":"int64","description":"id = 알림 PK — 읽음/삭제 요청의 pushId","example":88},"memberId":{"type":"integer","format":"int64","description":"선택 — memberId = 수신 회원 PK — null = 전체 발송(broadcast)","example":7},"title":{"type":"string","description":"title = 알림 제목","example":"처방전 접수 완료"},"body":{"type":"string","description":"body = 알림 본문","example":"약나루약국 남구점에서 처방전을 확인했습니다. 결제를 진행해 주세요."},"payload":{"type":"string","description":"선택 — payload = 앱 딥링크용 부가 데이터 (JSON 문자열)","example":{"screen":"OrderDetail","prescriptionSeq":101}},"relatedType":{"type":"string","description":"선택 — relatedType = 연관 대상 유형 — order 주문 / delivery 배송 / prescription_approved 조제가능 / prescription_rejected 조제불가 / eligibility 자격심사 / notice 공지 등","example":"order"},"relatedId":{"type":"integer","format":"int64","description":"선택 — relatedId = 연관 대상 PK (relatedType 별 — 주문/배송/처방은 처방전 id, eligibility 는 자격 신청 id)","example":101},"readAt":{"type":"string","format":"date-time","description":"선택 — readAt = 읽음 처리 일시 (ISO-8601) — null = 미읽음","example":"2026-09-11T10:05:00"},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 발송 일시 (ISO-8601)","example":"2026-09-11T09:45:00"}}},"PageMessageInfo":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/MessageInfo"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"PageableObject":{"type":"object","properties":{"paged":{"type":"boolean","description":"paged = 페이징 요청 여부"},"pageNumber":{"type":"integer","format":"int32","description":"pageNumber = 현재 페이지 번호 (0부터)"},"pageSize":{"type":"integer","format":"int32","description":"pageSize = 페이지 크기"},"offset":{"type":"integer","format":"int64","description":"offset = 건너뛴 항목 수 (page × size)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"unpaged":{"type":"boolean","description":"unpaged = 페이징 없이 전체 요청 여부"}}},"SortObject":{"type":"object","properties":{"sorted":{"type":"boolean","description":"sorted = 정렬 적용 여부"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"},"unsorted":{"type":"boolean","description":"unsorted = 정렬 미적용 여부"}}},"ApiResponseMapStringObject":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"object","additionalProperties":{},"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePagePharmacyView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PagePharmacyView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PagePharmacyView":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/PharmacyView"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseListOrderHistoryGroup":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/OrderHistoryGroup"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MedicineItem":{"type":"object","description":"주문 약품 1건 — 처방전 발급정보(issue_info)의 약품 라인","properties":{"drgCd":{"type":"string","description":"drgCd = 약품 코드 (EDI 보험코드 9자리)","example":640007270},"drgNm":{"type":"string","description":"drgNm = 약품명","example":"타이레놀정500mg"},"amount":{"type":"integer","format":"int32","description":"선택 — amount = 총 수량 — 현재 발급정보에 없어 항상 null","example":null},"dosage":{"type":"string","description":"선택 — dosage = 1회 투약량","example":1},"daysTotal":{"type":"string","description":"선택 — daysTotal = 총 투약 일수","example":3}}},"OrderHistoryGroup":{"type":"object","description":"주문 내역 날짜 그룹 — GET /api/v1/orders 응답 항목 (RN SectionList 용)","properties":{"targetDate":{"type":"string","description":"targetDate = 그룹 기준 주문 일자 (YYYY-MM-DD)","example":"2026-09-11"},"deliveryList":{"type":"array","description":"deliveryList = 해당 일자의 주문 카드 목록","items":{"$ref":"#/components/schemas/OrderListItem"}}}},"OrderListItem":{"type":"object","description":"주문 내역 카드 1건 — GET /api/v1/orders 의 날짜 그룹(deliveryList) 항목 (RN OrderHistory 화면)","properties":{"prescriptionSeq":{"type":"integer","format":"int64","description":"prescriptionSeq = 처방전(주문) PK — GET /api/v1/orders/detail?id= 의 id","example":101},"prescriptionStatus":{"type":"string","description":"prescriptionStatus = 주문 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료","example":"04"},"prescriptionStatusName":{"type":"string","description":"prescriptionStatusName = 주문 상태 한글 라벨 — 상태 코드에 대응","example":"결제완료"},"prescriptionRegdate":{"type":"string","description":"prescriptionRegdate = 주문(처방전 접수) 일자 (YYYY-MM-DD)","example":"2026-09-11"},"prescriptionPrice":{"type":"number","description":"선택 — prescriptionPrice = 약제비 (원) — 약국이 조제가능 처리 시 입력, 이전엔 null","example":12500},"totalPrice":{"type":"number","description":"선택 — totalPrice = 총 결제 금액 (원, 약제비 + 배송비)","example":15500},"receiveType":{"type":"string","description":"receiveType = 수령 방식 — onLine 택배배송 / offLine 방문수령","example":"onLine"},"unavailableReason":{"type":"string","description":"선택 — unavailableReason = 조제불가 사유 — 상태 03 일 때만","example":"재고 부족"},"pharmacyCode":{"type":"string","description":"선택 — pharmacyCode = 약국 코드 — GET /api/v1/pharmacies 의 pharmacyCode (PH-001 형식)","example":"PH-001"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명 (주문 시점 스냅샷)","example":"약나루약국 남구점"},"medicineList":{"type":"array","description":"medicineList = 약품 목록 — 목록 응답에서는 빈 배열, 상세에서 채움","items":{"$ref":"#/components/schemas/MedicineItem"}}}},"ApiResponseOrderDetail":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/OrderDetail","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"OrderDetail":{"type":"object","description":"주문 상세 — GET /api/v1/orders/detail?id= 및 관리자 GET /api/v1/admin/orders/detail?id= 응답 (RN MedicineOrderDetail 화면)","properties":{"prescriptionSeq":{"type":"integer","format":"int64","description":"prescriptionSeq = 처방전(주문) PK","example":101},"prescriptionStatus":{"type":"string","description":"prescriptionStatus = 주문 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료","example":"06"},"prescriptionStatusName":{"type":"string","description":"prescriptionStatusName = 주문 상태 한글 라벨","example":"배송중"},"unavailableReason":{"type":"string","description":"선택 — unavailableReason = 조제불가 사유 — 상태 03 일 때만","example":"재고 부족"},"reqDate":{"type":"string","description":"reqDate = 주문(처방전 접수) 일시 (ISO-8601)","example":"2026-09-11T09:30:00"},"receiveType":{"type":"string","description":"receiveType = 수령 방식 — onLine 택배배송 / offLine 방문수령","example":"onLine"},"prescriptionPrice":{"type":"number","description":"선택 — prescriptionPrice = 약제비 (원)","example":12500},"deliveryPrice":{"type":"number","description":"선택 — deliveryPrice = 배송비 (원) — offLine 은 0/null","example":3000},"totalPrice":{"type":"number","description":"선택 — totalPrice = 총 결제 금액 (원, 약제비 + 배송비)","example":15500},"medicineDirection":{"type":"string","description":"선택 — medicineDirection = 약사 복약 안내 (회원 노출)","example":"식후 30분에 1정씩 복용하세요."},"medicineList":{"type":"array","description":"medicineList = 처방 약품 목록","items":{"$ref":"#/components/schemas/MedicineItem"}},"pharmacyCode":{"type":"string","description":"선택 — pharmacyCode = 약국 코드 (PH-001 형식) — 조제불가(03) 후 다른 약국 재선택 시 거절 약국 식별용","example":"PH-001"},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명 (주문 시점 스냅샷)","example":"약나루약국 남구점"},"pharmacyPhone":{"type":"string","description":"pharmacyPhone = 약국 전화번호 (스냅샷)","example":"051-123-4567"},"pharmacyAddress":{"type":"string","description":"pharmacyAddress = 약국 주소 (스냅샷)","example":"부산광역시 남구 수영로 200"},"deliveryName":{"type":"string","description":"선택 — deliveryName = 수령인 이름 — onLine 배송지 스냅샷","example":"홍길동"},"deliveryPhone":{"type":"string","description":"선택 — deliveryPhone = 수령인 연락처 — onLine 배송지 스냅샷","example":"010-1234-5678"},"deliveryAddress":{"type":"string","description":"선택 — deliveryAddress = 배송 기본 주소 — onLine 배송지 스냅샷","example":"부산광역시 해운대구 센텀중앙로 79"},"deliveryDetailAddress":{"type":"string","description":"선택 — deliveryDetailAddress = 배송 상세 주소 (동/호수)","example":"101동 1203호"},"deliveryNumber":{"type":"string","description":"선택 — deliveryNumber = 택배 송장번호 — 배송중(06) 전환 시 약사 입력","example":6889012345678},"deliveryCompany":{"type":"string","description":"선택 — deliveryCompany = 택배사명 (CJ대한통운/우체국 등) — 배송중(06) 전환 시 약사 입력","example":"CJ대한통운"},"partnerInfo":{"$ref":"#/components/schemas/PartnerInfo","description":"선택 — partnerInfo = 처방전 발급 정보 (병원/의사/환자/진단) — null = 자가입력 또는 미연동"}}},"ApiResponseListCodeItemView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/CodeItemView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePageQnaView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageQnaView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageQnaView":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/QnaView"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseListCategoryView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/CategoryView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePagePostView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PagePostView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PagePostView":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/PostView"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponsePageSubstituteMedicineView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageSubstituteMedicineView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageSubstituteMedicineView":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/SubstituteMedicineView"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"SubstituteMedicineView":{"type":"object","description":"대체약품 분석 1건 — GET /api/v1/admin/substitute-medicines 목록, /lookup, /detail 응답 (원외처방 전후자료: 원처방 약품 + 3개월 사용량 + 대체 약품)","properties":{"id":{"type":"integer","format":"int64","description":"id = 대체약품 분석 PK (drug_substitute.substitute_id) — GET /api/v1/admin/substitute-medicines/detail?id= 의 id","example":17},"mainIngredientCode":{"type":"string","description":"mainIngredientCode = 주성분코드 — 대체 약품 매칭 키","example":"675801ATB"},"medicineCode":{"type":"string","description":"medicineCode = 원처방 품목코드 (약가코드 9자리, 앞자리 0 보존)","example":640007270},"medicineName":{"type":"string","description":"medicineName = 원처방 품목명","example":"타이레놀정500mg"},"maker":{"type":"string","description":"maker = 원처방 제약사명","example":"한국얀센"},"feeRate":{"type":"number","description":"선택 — feeRate = 원처방 수수료율 (%)","example":0.35},"feeAmount":{"type":"number","description":"선택 — feeAmount = 원처방 수수료 금액 (원)","example":12500},"totalQty3m":{"type":"number","description":"선택 — totalQty3m = 최근 3개월 총 처방 수량","example":1200},"totalAmount3m":{"type":"number","description":"선택 — totalAmount3m = 최근 3개월 총 처방 금액 (원)","example":3600000},"monthlyQty":{"type":"number","description":"선택 — monthlyQty = 월평균 처방 수량","example":400},"monthlyAmount":{"type":"number","description":"선택 — monthlyAmount = 월평균 처방 금액 (원)","example":1200000},"substituteMaker":{"type":"string","description":"선택 — substituteMaker = 대체 약품 제약사명 — 대체 약품 없으면 null","example":"한미약품"},"substituteMedicineName":{"type":"string","description":"선택 — substituteMedicineName = 대체 약품 품목명","example":"써스펜8시간이알서방정"},"substituteMedicineCode":{"type":"string","description":"선택 — substituteMedicineCode = 대체 약품 품목코드 (약가코드 9자리)","example":645500530},"substituteFeeRate":{"type":"number","description":"선택 — substituteFeeRate = 대체 약품 수수료율 (%)","example":0.45},"substituteFeeAmount":{"type":"number","description":"선택 — substituteFeeAmount = 대체 약품 수수료 금액 (원)","example":16200},"hasSubstitute":{"type":"boolean","description":"hasSubstitute = 대체 약품 존재 여부 — substituteMedicineCode 가 있으면 true","example":true},"filterMaker":{"type":"string","description":"선택 — filterMaker = 필터링용 제약사명 (원자료 필터 컬럼)","example":"한미약품"},"createdAt":{"type":"string","format":"date-time","description":"createdAt = 데이터 적재 일시 (ISO-8601)","example":"2026-08-01T00:00:00"}}},"ApiResponseListSubstituteMedicineView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/SubstituteMedicineView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseSubstituteMedicineView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/SubstituteMedicineView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseListRoleMenuView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/RoleMenuView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePagePrescriptionView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PagePrescriptionView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PagePrescriptionView":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/PrescriptionView"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseListPharmacyDocumentView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/PharmacyDocumentView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PharmacyDocumentView":{"type":"object","description":"약국 첨부 서류 1건 — GET /api/v1/admin/pharmacies/documents 응답 항목","properties":{"id":{"type":"integer","format":"int64","description":"id = 첨부 파일 PK (pharmacy_file.file_id)","example":5},"documentType":{"type":"string","description":"documentType = 서류 종류 — BUSINESS_LICENSE 사업자등록증 / PHARMACIST_LICENSE 약사 면허증 / OTHER 기타","example":"BUSINESS_LICENSE"},"fileName":{"type":"string","description":"fileName = 업로드 원본 파일명","example":"사업자등록증.pdf"},"fileSize":{"type":"integer","format":"int64","description":"fileSize = 파일 크기 (byte)","example":204800},"mimeType":{"type":"string","description":"mimeType = 파일 MIME 타입","example":"application/pdf"},"fileUrl":{"type":"string","description":"fileUrl = 다운로드 URL (/uploads/... 경로, UPLOAD_URL_PREFIX 접두)","example":"/uploads/pharmacy/6/2026-09-11/3f9c1a2b__license.pdf"}}},"ApiResponseListAdminUserSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/AdminUserSummary"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"AdminOrderRow":{"type":"object","description":"관리자 주문 목록 1행 — GET /api/v1/admin/orders 응답 항목 (평탄화, Excel 내보내기와 동일 컬럼)","properties":{"id":{"type":"integer","format":"int64","description":"id = 처방전(주문) PK — GET /api/v1/admin/orders/detail?id= 의 id","example":101},"status":{"type":"string","description":"status = 주문 상태 코드 — 01 발송 / 02 조제가능 / 03 조제불가 / 04 결제완료 / 05 조제완료 / 06 배송중 / 07 배송완료 / 08 미방문 / 09 오류 / 010 수령완료","example":"010"},"statusName":{"type":"string","description":"statusName = 주문 상태 한글 라벨","example":"수령완료"},"receiveType":{"type":"string","description":"receiveType = 수령 방식 — onLine 택배배송 / offLine 방문수령","example":"onLine"},"memberId":{"type":"integer","format":"int64","description":"memberId = 주문 회원 PK (member_info.member_id)","example":7},"memberName":{"type":"string","description":"memberName = 수령인 이름 (주문 시점 배송지 스냅샷)","example":"홍길동"},"memberPhone":{"type":"string","description":"memberPhone = 수령인 연락처 (주문 시점 배송지 스냅샷)","example":"010-1234-5678"},"pharmacyId":{"type":"integer","format":"int64","description":"pharmacyId = 약국 PK (pharmacy.pharmacy_id) — 검색 파라미터 pharmacyId 와 동일","example":1},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명 (스냅샷)","example":"약나루약국 남구점"},"prescriptionPrice":{"type":"number","description":"선택 — prescriptionPrice = 약제비 (원)","example":12500},"deliveryPrice":{"type":"number","description":"선택 — deliveryPrice = 배송비 (원)","example":3000},"totalPrice":{"type":"number","description":"선택 — totalPrice = 총 결제 금액 (원)","example":15500},"deliveryNumber":{"type":"string","description":"선택 — deliveryNumber = 택배 송장번호","example":6889012345678},"deliveryCompany":{"type":"string","description":"선택 — deliveryCompany = 택배사명 (CJ대한통운/우체국 등) — 배송중(06) 전환 시 약사 입력","example":"CJ대한통운"},"reqDate":{"type":"string","description":"reqDate = 주문(처방전 접수) 일시 (ISO-8601)","example":"2026-09-11T09:30:00"}}},"ApiResponsePageAdminOrderRow":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageAdminOrderRow","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageAdminOrderRow":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/AdminOrderRow"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"AdminRevenueRow":{"type":"object","description":"약국별 매출 집계 1행 — GET /api/v1/admin/orders/revenue 응답의 rows 항목","properties":{"pharmacyId":{"type":"integer","format":"int64","description":"pharmacyId = 약국 PK (pharmacy.pharmacy_id)","example":1},"pharmacyName":{"type":"string","description":"pharmacyName = 약국명","example":"약나루약국 남구점"},"orderCount":{"type":"integer","format":"int64","description":"orderCount = 집계 대상 주문 건수","example":42},"totalSum":{"type":"number","description":"totalSum = 총 결제 금액 합계 (원)","example":651000},"prescriptionSum":{"type":"number","description":"prescriptionSum = 약제비 합계 (원)","example":525000},"deliverySum":{"type":"number","description":"deliverySum = 배송비 합계 (원)","example":126000}}},"AdminRevenueSummary":{"type":"object","description":"매출 정산 응답 — GET /api/v1/admin/orders/revenue (약국별 행 + 총합, 조회 조건 에코)","properties":{"rows":{"type":"array","description":"rows = 약국별 매출 집계 행 목록","items":{"$ref":"#/components/schemas/AdminRevenueRow"}},"totalOrderCount":{"type":"integer","format":"int64","description":"totalOrderCount = 전체 주문 건수 (rows 합)","example":120},"totalRevenueSum":{"type":"number","description":"totalRevenueSum = 전체 결제 금액 합계 (원)","example":1860000},"dateFrom":{"type":"string","description":"선택 — dateFrom = 조회 시작일 (YYYY-MM-DD, 요청 파라미터 에코) — null = 제한 없음","example":"2026-09-01"},"dateTo":{"type":"string","description":"선택 — dateTo = 조회 종료일 (YYYY-MM-DD, 요청 파라미터 에코) — null = 제한 없음","example":"2026-09-30"},"status":{"type":"string","description":"선택 — status = 집계 대상 주문 상태 코드 (기본 010 수령완료) — null = 상태 무시","example":"010"}}},"ApiResponseAdminRevenueSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/AdminRevenueSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseListMenuView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/MenuView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseListMyMenuView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/MyMenuView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"MyMenuView":{"type":"object","description":"로그인한 관리자의 사이드바 메뉴 — GET /api/v1/admin/menus/my 응답 항목","properties":{"menuCode":{"type":"string","description":"menuCode = 메뉴코드 — 관리자웹 라우트 key","example":"prescriptionMgt"},"menuName":{"type":"string","description":"menuName = 메뉴명","example":"처방전 관리"},"menuPath":{"type":"string","description":"선택 — menuPath = 이동 경로","example":"/prescriptionMgt"},"menuIcon":{"type":"string","description":"선택 — menuIcon = antd 아이콘 이름","example":"FileTextOutlined"},"children":{"description":"children = 하위 메뉴 — 없으면 빈 배열"}}},"ApiResponsePageAdminMemberSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageAdminMemberSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageAdminMemberSummary":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/AdminMemberSummary"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseListPharmacyView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/PharmacyView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePageEligibilitySummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageEligibilitySummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageEligibilitySummary":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/EligibilitySummary"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseStatusView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/StatusView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"StatusView":{"type":"object","description":"약품 마스터 적재 현황","properties":{"count":{"type":"integer","format":"int64","description":"count = 현재 적재된 약품 수","example":21998},"lastLoadedAt":{"type":"string","description":"lastLoadedAt = 선택 — 마지막 적재 일시 (ISO-8601), 적재 이력이 없으면 null","example":"2026-08-19T17:04:25"}}},"ApiResponseDrugLookupView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/DrugLookupView","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"DrugLookupView":{"type":"object","description":"약품 코드 조회 결과 — 약품명 + 같은 코드의 대체약품 목록 (프론트 1회 호출)","properties":{"ediCode":{"type":"string","description":"ediCode = 조회한 EDI(보험) 약품코드 9자리","example":661700390},"name":{"type":"string","description":"name = 약품명 — source 가 MASTER 면 마스터 제품명, SUBSTITUTE 면 대체약품 자료의 원처방 약품명, NONE 이면 null"},"company":{"type":"string","description":"company = 선택 — 제조/수입사"},"price":{"type":"number","description":"price = 선택 — 급여 상한금액(원). source 가 MASTER 일 때만"},"source":{"type":"string","description":"source = 약품명 출처 — MASTER(약품 마스터) / SUBSTITUTE(대체약품 자료) / NONE(미등록)","example":"MASTER"},"substitutes":{"type":"array","description":"substitutes = 같은 원처방 코드의 대체약품 목록 (없으면 빈 배열)","items":{"$ref":"#/components/schemas/SubstituteMedicineView"}}}},"ApiResponseDashboardSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/DashboardSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"Counts":{"type":"object","description":"상태별 처리 대기 건수","properties":{"todayNew":{"type":"integer","format":"int64","description":"todayNew = 오늘 새로 접수된 처방전 수 (01 발송 상태)","example":3},"paymentWaiting":{"type":"integer","format":"int64","description":"paymentWaiting = 결제 대기 건수 (02 조제가능)","example":2},"shipping":{"type":"integer","format":"int64","description":"shipping = 배송 중 건수 (06 배송중)","example":1}}},"DashboardSummary":{"type":"object","description":"관리자 대시보드 요약 — 약사는 자기 약국만, 운영자는 전체","properties":{"counts":{"$ref":"#/components/schemas/Counts","description":"counts = 상태별 처리 대기 건수"},"monthRevenue":{"type":"number","description":"monthRevenue = 이번 달 매출(원) — 수령완료(010) 주문 기준","example":1250000},"monthOrderCount":{"type":"integer","format":"int64","description":"monthOrderCount = 이번 달 수령완료(010) 주문 수","example":42},"recent":{"type":"array","description":"recent = 최근 처방전 5건 (상태 무관, 최신순)","items":{"$ref":"#/components/schemas/PrescriptionView"}},"asOf":{"type":"string","format":"date-time","description":"asOf = 집계 시각 (ISO-8601)","example":"2026-09-11T16:55:42"},"period":{"$ref":"#/components/schemas/Period","description":"period = 매출 집계 기간 — 이번 달 1일 ~ 오늘"}}},"Period":{"type":"object","description":"집계 기간","properties":{"from":{"type":"string","format":"date","description":"from = 시작일 (YYYY-MM-DD)","example":"2026-09-01"},"to":{"type":"string","format":"date","description":"to = 종료일 (YYYY-MM-DD)","example":"2026-09-11"}}},"ApiResponseListCodeGroupView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/CodeGroupView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponseMapStringListCodeItemView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/CodeItemView"}},"description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"ApiResponsePageAdminUserSummary":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"$ref":"#/components/schemas/PageAdminUserSummary","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략"},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}},"PageAdminUserSummary":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64","description":"totalElements = 조건에 맞는 전체 건수"},"totalPages":{"type":"integer","format":"int32","description":"totalPages = 전체 페이지 수"},"pageable":{"$ref":"#/components/schemas/PageableObject","description":"pageable = 요청 페이지 정보"},"size":{"type":"integer","format":"int32","description":"size = 페이지 크기 (요청의 perPage)"},"content":{"type":"array","description":"content = 이 페이지의 항목 목록","items":{"$ref":"#/components/schemas/AdminUserSummary"}},"number":{"type":"integer","format":"int32","description":"number = 현재 페이지 번호 (0부터)"},"sort":{"$ref":"#/components/schemas/SortObject","description":"sort = 정렬 정보"},"first":{"type":"boolean","description":"first = 첫 페이지 여부"},"last":{"type":"boolean","description":"last = 마지막 페이지 여부 — true 면 더 불러올 것이 없다"},"numberOfElements":{"type":"integer","format":"int32","description":"numberOfElements = 이 페이지에 실제로 담긴 항목 수"},"empty":{"type":"boolean","description":"empty = 결과가 비었는지 여부"}}},"ApiResponseListAddressView":{"type":"object","description":"공통 응답 래퍼 — 성공 시 data, 실패 시 error 가 채워진다 (null 필드는 생략)","properties":{"success":{"type":"boolean","description":"success = 처리 성공 여부 — false 면 error 를 확인","example":true},"data":{"type":"array","description":"data = 응답 본문 — 오퍼레이션마다 형태가 다르다. 실패 시 생략","items":{"$ref":"#/components/schemas/AddressView"}},"meta":{"$ref":"#/components/schemas/Meta","description":"meta = 선택 — 목록 응답의 페이지 정보 (일부 목록 API 만)"},"error":{"$ref":"#/components/schemas/ErrorBody","description":"error = 실패 시에만 — { code, message }"}}}},"securitySchemes":{"bearerAuth":{"type":"http","description":"앱 회원 토큰(/api/v1/auth/login) 또는 관리자 토큰(/api/v1/admin/auth/login)의 accessToken 을 그대로 입력한다.","scheme":"bearer","bearerFormat":"JWT"}}}}