{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API URL (task-01)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"* 심평원 다건요청(기본+자동차) 단일인증 다건수집 API path (task-06)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":25,"line_end":25,"block_type":"line","text":"* (예약) 국세청 연말정산간소화 의료비 API path — task-07용, 현재 미사용","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* 진료내역 스크래핑 공급자 스위치: 'codef'(기본) | 'coocon' | 'octover' | 'hyphen' | 'multi'(분산)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* Redis (멀티 분산 카운터/큐). 예: redis://insuniverse-stg-redis...:6379","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 멀티('multi') 분산 풀: \"key:분당한도:플로우비용:단가\" 콤마구분. 비용 싼 곳 우선.","hangul_chars":26,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 자동차보험 진료 수집 ON/OFF. 미설정/DB 장애 시 fail-closed(OFF), 명시적 true만 ON.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* 게이트웨이 URL (dev: https://dev2.coocon.co.kr:8443/domestic/finance/scrap/smart_gateway.jsp)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 간편인증 AES256-CBC 사용 여부 (기본 false=평문). true면 gwUrl을 _aes.jsp로 사용","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"* AES256 키(32byte)/IV(16byte) — 쿠콘 이용고객별 발급 ([참조2])","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"* RSA-OAEP 공개키 PEM (미설정 시 번들 기본키 사용) — 보통 안 넣어도 됨","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* (분당 한도는 TREAT_POOL 에서 관리 — 여기 두지 않음)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 인포텍 API 게이트웨이 (미설정 시 https://apigw.infotech.co.kr/api/service)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 발급키 — 요청 헤더 api-cloud-key (개발/운영 별도)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* 어플리케이션코드 — 요청 바디 appCd (예: 업체명-api)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":73,"line_end":74,"block_type":"line","text":"* 인포텍 실행 타임아웃(초, 요청 바디 exeTimeout) — 미설정 시 300(5분).\n*   자료 과다 유저의 수집 세션 조기종료(B0002-999) 완화용. axios(330s)보다 작게 둘 것.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* 자체 스크래퍼 엔진(scraper-engine) 베이스 URL. 미설정/풀 미등록 시 'inhouse' 공급자는 비활성.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* 엔진 호출 인증키 — 엔진 INHOUSE_API_KEY와 일치해야 함(PII 네트워크 경유 보호)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* 자체엔진 자동차 내부 카나리. 기본 OFF, 멀티 디스패처에서 inhouse로 선택된 요청에만 적용.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"* 간편인증 인증확인 알림톡 템플릿코드 (Aligo 템플릿 승인 후 주입)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/config/configuration.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"* 외부 서비스(보상닥터 등) 쿠콘 바이패스: 동시 슬롯 상한(client별). 쿠콘 인증키는 서버 보유.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":2,"line_end":10,"block_type":"jsdoc","text":"각 기능에 따른 코드 앞에 두자리\n관리자 (01)\n기업 (02)\nFC (03)\n인증 (06)\n엑셀 (08)\n청구서 (09)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"영업대리점(10)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":60,"line_end":61,"block_type":"line","text":"기업조직/계약 1:N 신규 (task-688)\n* 사전 확정 설계 계약 기준 — 동일 코드가 기존 다른 곳에서 사용 중일 수 있으나, 호출 컨텍스트(조직/계약/회원) 분리로 충돌 없음.","hangul_chars":57,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 조직트리 이동 순환 차단(task: 조직트리 관리) — 자기 자신/자기 하위로 이동 금지.","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* 회원 소속 일괄배정/조직관리자 지정 — 대상 회원 없음/기업 불일치.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/admin.constant.ts","lang":"js","line_start":81,"line_end":82,"block_type":"line","text":"기업계약 구독계정수(seat) 하한 판정 (후불정산·기업계약 변경안 3-4)\n* 프론트는 code 문자열과 data.{current,after,seat}를 그대로 읽는다 — 계약 유지 필수.","hangul_chars":45,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":23,"line_end":33,"block_type":"jsdoc","text":"각 기능에 따른 코드 앞에 두자리\n구독(01)\n주문/결제(02)\n알림톡(03)\n분석(04)\n분석결과(05)\n인증(06)\nFC(07)\n기타 (08)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"주문/결제(02)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"* 초대 알림톡 링크 접근 차단(구독종료/건수소진/결제취소) — 프론트가 \"접근 기간 만료\" 화면 노출","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"분석결과(05)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"손해사정서비스(09)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/api.constant.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"* 내/외부공통에러코드 (ex: *E999)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/client.constant.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"내/외부공통에러코드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/client.constant.ts","lang":"js","line_start":20,"line_end":26,"block_type":"jsdoc","text":"각 기능에 따른 코드 앞에 두자리\n기본요청(00)\n계약정보(01)\n주문(02)\n분석(03)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/client.constant.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"기본요청(00)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/constants/client.constant.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"계약정보(01)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* 해당 키가 없는 케이스가 있으므로 해당 키로 넘어온게 있는지 검증","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"* 처리 벤더(없으면 codef) — coocon/octover/hyphen native코드도 category·retryable 해석","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 기존 stage별 응답을 그대로 결정(회귀 방지) — 상수는 부착 시 복제됨","hangul_chars":24,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 잘못된 개인정보입니다.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* 앱을 설치하지 않았거나 인증서를 발급받지 않으셨습니다.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* 인증 타임아웃 | 인증 3회 이상 | 이미 응답이 완료된 경우","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/codef-exception.filter.ts","lang":"js","line_start":98,"line_end":99,"block_type":"line","text":"* 기존 응답 형태 유지 + 통합 분류·재시도성 부착\n*   (프론트가 retryable로 '일시오류 재시도 vs 진짜실패' 분기 — 갭 A 해결)","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/fliters/institution-block-exception.filter.ts","lang":"js","line_start":10,"line_end":11,"block_type":"line","text":"* 기관 사용중지(InstitutionBlockException) 발생 시 응답 그대로 직렬화하여 내려준다.\n* 응답 본문에는 팝업 안내(타입/제목/내용/이미지/기간)가 포함되어 있어 프론트는 그대로 팝업으로 렌더하면 된다.","hangul_chars":68,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/admin-viewer.helper.ts","lang":"js","line_start":1,"line_end":6,"block_type":"line","text":"* 관리자 열람(admin-view iframe) — 회원 소유자 검증의 대체 통과 경로 판정.\n*\n* 배경(2026-07): 소유자 검증(fix/security 커밋들)이 회원 JWT 기준이라, 회원 JWT가 없는\n*  관리자 분석 팝업(iframe)의 병력분석 진료로그·추천보험·투약/검사 추천 조회가 403으로\n*  차단됐다. admin JWT(_aaT 쿠키, SameSite=None이라 iframe XHR에도 실림)가 함께 온\n*  요청은 관리자 권한으로 대신 검증한다. (AdminOptionalGuard가 req['admin']을 복원)","hangul_chars":110,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/admin-viewer.helper.ts","lang":"js","line_start":12,"line_end":13,"block_type":"line","text":"* AdminOptionalGuard가 admin-view 단명 토큰(scope 'analyze' + oddId) 검증에 성공하면 세팅.\n*  쿠키(_aaT)가 iframe 요청에 실리지 않는 환경(로컬 admin ↔ stg 사이트 등)의 대체 경로.","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/admin-viewer.helper.ts","lang":"js","line_start":17,"line_end":23,"block_type":"jsdoc","text":"통합관리자(admin)는 전체 열람(기존 admin-view 정책과 동일),\n기업/조직관리자(corp)는 자기 기업(agcId) 소속 건만 열람.\nadmin-view 단명 토큰이 해당 oddId로 검증된 요청은 역할 무관 통과 —\n발급 시점에 관리자 인증(AdminJwtAuthGuard) + corp 기업 스코프(isOddInCorpScope)가 이미 검증됨.\n영업대리점(sales) 등 그 외 역할은 통과시키지 않는다.","hangul_chars":95,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/cookie.helper.ts","lang":"js","line_start":5,"line_end":13,"block_type":"jsdoc","text":"_aT 인증쿠키 공통 옵션.\n - signin/refresh(set)·signout(clear)이 **동일 옵션**을 써야 옛 쿠키가 정상적으로 덮어써지고\n   삭제된다. 옵션 불일치 시 옛 쿠키가 안 치워져 누적되고, 만료된 옛 _aT 가 먼저 읽혀 메인 API 401 → 튕김.\n - 앱은 www ↔ api 크로스사이트라 https 환경에선 sameSite='none' + secure 가 필수다.\n   (sameSite=Lax(기본)면 cross-site XHR 에 쿠키가 안 실려 로그인 직후 메인 API 가 401 난다.)\n - 로컬(http) 개발은 secure 쿠키가 불가하므로 lax 로 폴백한다.\n   ※ prod 의 NODE_ENV 가 'dev' 라 NODE_ENV 로 분기하면 안 되고, 요청의 https 여부로 판단한다.","hangul_chars":141,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/cookie.helper.ts","lang":"js","line_start":29,"line_end":37,"block_type":"jsdoc","text":"인증 토큰 후보 목록 추출 (raw Cookie 헤더의 모든 _aT + Authorization Bearer).\n - 과거 로그인의 옛 _aT(만료, 다른 path/속성)가 안 지워진 채 새 _aT와 공존하면\n   `Cookie: _aT=옛만료; _aT=새것` 처럼 _aT가 여러 개 전송된다. 이때 cookie-parser는\n   **첫 번째(옛 만료)** 만 req.cookies에 담아, 서버가 만료 토큰을 읽고 401 → 로그인 직후 튕김.\n   (prod 로그 실측: signin 직후 cookie=[mem옛/만료, mem새/유효] 인데 401 다발)\n - 그래서 단일 토큰이 아니라 **후보 전부**를 돌려주고, 가드가 verify 성공하는 토큰을 고른다.\n - Authorization 헤더(프론트 저장 토큰)도 후보에 포함해 쿠키 미전송 기기까지 커버한다.","hangul_chars":163,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/date.helper.ts","lang":"js","line_start":3,"line_end":3,"block_type":"line","text":"전체 월 범위 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/date.helper.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"전체 일 범위 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/device.helper.ts","lang":"js","line_start":2,"line_end":2,"block_type":"line","text":"* 앱환경 구분을 위해 네이티브에서 userAgent값에 추가 해놓아 해당 값을 구분값으로 사용","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/flatten.ts","lang":"js","line_start":11,"line_end":11,"block_type":"line","text":"재귀적으로 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/flatten.ts","lang":"js","line_start":13,"line_end":13,"block_type":"line","text":"최종 값을 result에 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/format.helper.ts","lang":"js","line_start":17,"line_end":17,"block_type":"line","text":"날짜 포멧팅","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":1,"line_end":5,"block_type":"line","text":"* 주민등록번호 사전검증 — 체크섬·생년월일·성별/세기코드·만나이·이름 (외부 API 0, 즉시).\n* 목적: 잘못된 입력(랜덤/오타/형식오류/미성년)을 대기열·codef 진입 전에 걸러 자원 낭비 차단.\n* 한계: \"이 번호가 이 이름의 실존 인물인지(매핑)\"는 본인확인기관(NICE/KCB/행안부) 영역이라\n*       직접 검증 불가 → codef 본인인증(certify)이 통신사 명의확인으로 담당.\n*       실명확인 계약 시 treat.service의 hook에 매핑확인을 끼우면 대기열 전 명의 거르기 가능.","hangul_chars":148,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"* 만 14세 미만 차단(만 14세부터 이용 가능). 정책 변경 시 이 값만 조정.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":13,"line_end":18,"block_type":"jsdoc","text":"주민등록번호 입력 사전검증.\n@param name 이름\n@param birth6 앞 6자리(YYMMDD)\n@param identity7 뒤 7자리","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 1) 이름 — 한글/영문 2자 이상 (외국인 영문명 허용, 숫자/특수문자 차단)","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* 2) 형식 — 앞 6 / 뒤 7 숫자","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"* 3) 성별/세기 코드 (뒷자리 첫 숫자) — 1,2,5,6:1900s / 3,4,7,8:2000s / 9,0:1800s","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"* 4) 생년월일 실재 여부 (130230=2월30일 같은 가짜 날짜·미래 날짜 차단)","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":65,"line_end":66,"block_type":"line","text":"* 5) 체크섬(가중치 합 mod 11) — 내국인 한정.\n*    외국인등록번호(성별코드 5~8)는 검증식이 달라 정상번호 오탐 방지를 위해 체크섬은 건너뜀.","hangul_chars":48,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/identity.helper.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* 6) 만 나이 — 만 14세 미만 차단 (만 14세 생일부터 이용 가능, codef·심평원 정책 일치)","hangul_chars":26,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":1,"line_end":1,"block_type":"line","text":"* 이름 마스킹 함수","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"* 연락처 마스킹 함수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"1. 숫자만 추출","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":15,"line_end":15,"block_type":"line","text":"숫자만 남김","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":17,"line_end":17,"block_type":"line","text":"2. 자리 수에 따라 하이픈 포맷 지정","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":25,"line_end":25,"block_type":"line","text":"자리수 맞지 않으면 그대로 리턴","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"3. 생년월일 마스킹 함수 (예: 900101 → 90****)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"앞 2자리 또는 4자리 연도 포함 가능","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"4. 이메일 마스킹 함수 (예: abc****@gmail.com)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"null, undefined, 빈 문자열 처리","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"아이디 최소 길이 규칙","hangul_chars":9,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"노출할 앞자리 개수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"1. 전체 마스킹:","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"길이가 0이면 * 하나 반환 (빈 문자열 위에서 이미 처리)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"4자리 이상인 경우, 앞 3자리 노출 후 나머지 마스킹","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/mask.helper.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 통합 마스킹 함수","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/sanitize.helper.ts","lang":"js","line_start":3,"line_end":3,"block_type":"line","text":"* 기업별 약관 본문(agtContent) 저장형 XSS 차단용 화이트리스트 옵션","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/sanitize.helper.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* javascript: 등 위험 스킴 차단, 허용 스킴만 통과","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/sanitize.helper.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* 화이트리스트에 없는 태그(script·style·iframe 등)는 통째로 제거","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/sanitize.helper.ts","lang":"js","line_start":51,"line_end":52,"block_type":"line","text":"* HTML 약관 본문을 화이트리스트 기반으로 정제하여 저장형 XSS를 차단한다.\n* 입력이 null/undefined면 그대로 반환하여 호출부의 타입을 보존한다.","hangul_chars":49,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/translate.helper.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* FC 기업 회원의 경우 탈퇴 - 중지, 가입 - 사용 사용상태로 프론트에서 표기되어 추가","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/uid.helper.ts","lang":"js","line_start":4,"line_end":4,"block_type":"line","text":"* 랜덤 Uuid 생성(구독번호 / 주문번호 생성시 사용)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/uid.helper.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"* ULID Crockford base32 알파벳 (외부 의존성 없이 자체 구현)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/helpers/uid.helper.ts","lang":"js","line_start":35,"line_end":39,"block_type":"jsdoc","text":"ULID(26자, Crockford base32) 생성기.\n- 사전 정렬 가능한 시간기반 prefix(10자) + 랜덤(16자).\n- 외부 패키지 도입 없이 Node 표준 crypto만 사용.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/interceptors/api-response.interceptor.ts","lang":"js","line_start":11,"line_end":13,"block_type":"jsdoc","text":"정상응답 시 API 응답 포맷을 통일시키는 인터셉터","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/interceptors/client-response.interceptor.ts","lang":"js","line_start":11,"line_end":13,"block_type":"jsdoc","text":"정상응답 시 API 응답 포맷을 통일시키는 인터셉터","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/main.ts","lang":"js","line_start":32,"line_end":33,"block_type":"line","text":"* 대용량 엑셀 스트리밍 다운로드(분석관리 등 10만행+)가 Node 기본 requestTimeout(5분)에\n*   \"request aborted\"로 끊기던 문제 → 30분으로 상향. headersTimeout(기본 60초)은 유지.","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.controller.ts","lang":"js","line_start":21,"line_end":25,"block_type":"jsdoc","text":"★보안(C2): admin(AdminJwtAuthGuard 보호)이 특정 분석건(type+id)에 스코프된 단명 토큰을 발급받는 엔드포인트.\n  admin 팝업이 이 토큰을 iframe URL ?t= 로 실어 site admin-view 를 띄우면, site→server admin-view 호출이\n  토큰으로 인가된다. 관리자만(AdminJwtAuthGuard) 발급 가능하므로 순차 id 순회 IDOR가 막힌다.","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.controller.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* corp는 분석 상세팝업(레벨2) 허용 기업만 admin-view 토큰 발급 가능","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.guard.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"* 완전 검증된 v2 토큰만 관리자 identity를 복원한다. legacy/invalid는 자동차 guard가 fail-closed.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.guard.ts","lang":"js","line_start":46,"line_end":48,"block_type":"line","text":"* ★게이트(무중단 롤아웃): ADMIN_VIEW_TOKEN_ENFORCE='true' 일 때만 차단한다. 그 전엔 미검증도 통과\n*   (경고 로그만) → admin/site가 토큰을 실제로 전달하는지 운영에서 확인한 뒤 플래그를 켜면 IDOR 차단\n*   활성. 코드 배포만으론 기존 iframe이 안 깨진다.","hangul_chars":74,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.module.ts","lang":"js","line_start":7,"line_end":10,"block_type":"jsdoc","text":"★보안(C2): admin-view IDOR 차단용 단명 HMAC 토큰. 발급(컨트롤러)+검증(가드).\n  guard/service를 export → 각 admin-view 모듈이 import해서 컨트롤러에 @UseGuards(AdminViewTokenGuard) 적용.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.service.ts","lang":"js","line_start":13,"line_end":18,"block_type":"jsdoc","text":"★보안(C2): admin-view/* 는 admin→site cross-origin iframe이라 세션 쿠키를 못 싣는다(IDOR였음).\n  세션 가드 대신 \"scope+id로 스코프된 단명(短命) HMAC 토큰\"을 admin 백엔드(AdminJwtAuthGuard 보호)가\n  발급 → iframe URL ?t= 로 전달 → 여기서 검증. 토큰은 특정 분석건(scope:id)에만 유효 + TTL.\n  순차 정수 id를 순회해도 유효 토큰 없이는 못 본다.","hangul_chars":79,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.service.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"ADMIN_VIEW_SECRET 우선, 없으면 AES_SECRET 재사용(둘 다 없으면 빈키 → verify 항상 실패=안전).","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.service.ts","lang":"js","line_start":28,"line_end":28,"block_type":"jsdoc","text":"scope+id와 발급 관리자의 자동차 조회 claim을 함께 서명한다.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"jsdoc","text":"서명·scope·id·만료를 모두 검증한 claim만 반환한다.","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin-view-token/admin-view-token.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"* 기존 scope:id:exp 토큰은 일반 admin-view에만 호환한다.","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/admin/admin.repository.ts","lang":"js","line_start":185,"line_end":187,"block_type":"line","text":"* 조직관리자 로그인 조회 — 기업(agcLoginId) 내 mem_is_org_manager=1 기업회원(MEM002).\n*   관리 org의 org_path를 함께 반환(부분트리 스코프 payload용).\n* 기업 식별은 공개용 기업코드(agcCorporateCode) 기준 (2026-07 기획 — 로그인 입력값 변경)","hangul_chars":57,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":137,"line_end":137,"block_type":"line","text":"* 랜덤 혹은 고정 여부에 따른 쿼리 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"* 광고 통계","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":209,"line_end":209,"block_type":"line","text":"전월/전일 대비 계산을 위하여 전월/전일 날짜 계산","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":243,"line_end":243,"block_type":"line","text":"* 유저 광고 목록 조회시 노출수 증가","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":248,"line_end":248,"block_type":"line","text":"* 광고 노출수 통계테이블 upsert","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":264,"line_end":264,"block_type":"line","text":"* 광고테이블 총 노출수 증가","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":274,"line_end":274,"block_type":"line","text":"* 클릭수/재생수 증가","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":279,"line_end":279,"block_type":"line","text":"* 광고 토탈 카운트 업데이트","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":297,"line_end":297,"block_type":"line","text":"* 광고통계 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.repository.ts","lang":"js","line_start":318,"line_end":318,"block_type":"line","text":"* 기업 광고 카운트(위치별)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 이미지 타입일 경우 업로드 로직","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":103,"line_end":103,"block_type":"line","text":"* 광고 통계 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"기간 내 광고통계 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":142,"line_end":142,"block_type":"line","text":"* 요청개수에 따라 고정 광고 우선적으로 채워넣고 남은 광고를 랜덤 광고로 채워넣는 방식","hangul_chars":36,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":173,"line_end":173,"block_type":"line","text":"* 광고 동영상/이미지 클릭시 카운트 증가","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":201,"line_end":201,"block_type":"line","text":"* 광고 이미지 데이터","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":210,"line_end":210,"block_type":"line","text":"* s3 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":332,"line_end":332,"block_type":"line","text":"* 배열 복사","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":359,"line_end":359,"block_type":"line","text":"* 고정광고 GET","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":369,"line_end":369,"block_type":"line","text":"* 모든 랜덤광고 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":376,"line_end":376,"block_type":"line","text":"* 셔플 로직 실행","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":390,"line_end":390,"block_type":"line","text":"* 필요 광고 계산","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":395,"line_end":395,"block_type":"line","text":"* 모든 랜덤광고 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/advertisement/advertisement.service.ts","lang":"js","line_start":399,"line_end":399,"block_type":"line","text":"* 셔플 로직 실행","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency-admin.controller.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency-admin.controller.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업만 조회","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency-admin.dto.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"TODO: tnSalesAgency entity.ts 추가 시 SalesAgency 경로 수정 필요","hangul_chars":9,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency-admin.dto.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"TODO: tnSalesAgency entity.ts 추가 시 SalesAgency 경로 수정 필요","hangul_chars":9,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency-admin.dto.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"TODO: tnSalesAgency entity.ts 추가 시 SalesAgency 경로 수정 필요","hangul_chars":9,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency.repository.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"비밀번호 해싱 (bcrypt, salt rounds: 10)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency.repository.ts","lang":"js","line_start":197,"line_end":197,"block_type":"line","text":"비밀번호가 입력된 경우에만 해싱","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/agency.repository.ts","lang":"js","line_start":287,"line_end":287,"block_type":"line","text":"* 영업대리점 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.controller.ts","lang":"js","line_start":23,"line_end":27,"block_type":"jsdoc","text":"[기업관리자 콘솔] 마이페이지 (2026-07 기획, company-mockup/기업조직관리자_콘솔.html)\n- 기업관리자(SUPER) = 기업정보(비밀번호·회계이메일 수정), 조직관리자(ORG) = 내 정보\n- 진입 전 현재 비밀번호 검증(verify-password) 필수 흐름은 프런트에서 처리","hangul_chars":74,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.controller.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"* 기업관리자(SUPER) 전용 — 조직관리자(ORG) 차단","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.controller.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 조직관리자(ORG) 전용","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.dto.ts","lang":"js","line_start":4,"line_end":4,"block_type":"line","text":"* 비밀번호 정책: 8~16자리 영문자·숫자·특수문자(!@#$%^&*) 조합 (목업 안내 문구와 동일)","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.dto.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"* 마이페이지 진입 본인확인 — 로그인 계정의 현재 비밀번호 검증 (목업 개발팀 전달)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.dto.ts","lang":"js","line_start":17,"line_end":17,"block_type":"line","text":"* 기업관리자 마이페이지(기업정보) — 비밀번호·회계팀 이메일만 수정 가능","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.dto.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* 조직관리자 마이페이지(내 정보) — 회원명·연락처·이메일·비밀번호 변경 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.service.ts","lang":"js","line_start":10,"line_end":16,"block_type":"jsdoc","text":"기업/조직관리자 마이페이지 (2026-07 기획, company-mockup/기업조직관리자_콘솔.html)\n- 기업관리자(SUPER): 기업정보 조회 + 비밀번호·회계팀 이메일만 수정\n  (접근차단상태·계약종료여부는 미노출)\n- 조직관리자(ORG): 내 정보 조회 + 회원명·연락처·이메일·비밀번호 수정\n- 마이페이지 진입 전 현재 비밀번호 검증","hangul_chars":104,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.service.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 최신 계약 1건 — 회계팀 이메일의 저장 위치(tn_agency_contract.act_accounting_email)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/agency/corp-my.service.ts","lang":"js","line_start":132,"line_end":132,"block_type":"line","text":"* 마이페이지 진입 본인확인 — SUPER는 기업 비밀번호, ORG는 회원 비밀번호 대조","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.dto.ts","lang":"js","line_start":89,"line_end":89,"block_type":"line","text":"* 과금방식/구독계정수 하한/회계팀 이메일(후불정산 변경안)","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.dto.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* 과금방식/구독계정수 하한/회계팀 이메일(후불정산 변경안)","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.dto.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"* 해당 기업의 현재 활성 구독계정수(최신 구독상태='구독' 회원수) — 상세 조회에서만 세팅.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"계약시작일이 계약종료일보다 클 수 없음","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"중복되는 계약(계약일자 범위)이 존재하는지 확인","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"계약시작일이 계약종료일보다 클 수 없음","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"중복되는 계약(계약일자 범위)이 존재하는지 확인","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":101,"line_end":103,"block_type":"line","text":"* 과금방식 검증(후불정산 변경안)\n*  - PREPAID(선불)는 추후 지원 — 등록/수정 거부.\n*  - 회계팀 이메일(actAccountingEmail)은 선택값 — 미입력 시 정산 메일 발송 시점에 입력 안내.","hangul_chars":53,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 구독중인 상품이 있을 때 계약이 삭제되지 않도록 조치","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"* 구독중인 상품이 있는 계약의 코드 추출 및 count 체크","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract-admin.service.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"* 계약에 구독 중인 회원이 있을 경우 exception 발생","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract.entity.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"* 과금방식(act_billing_type). PREPAID는 추후 지원 — 등록/수정에서 서버가 거부한다.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract.entity.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 과금방식(후불정산 변경안): PREPAID/POSTPAID/FREE. PREPAID는 등록/수정 시 서버가 거부.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract.entity.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 계약 구독계정수 하한(후불정산 변경안). NULL이면 사용중지/구독해지 seat 하한 판정 skip.","hangul_chars":30,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract.entity.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 회계팀 이메일(후불정산 변경안). FREE 계약은 선택, 그 외 필수(서비스에서 검증).","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/contract/contract.repository.ts","lang":"js","line_start":186,"line_end":187,"block_type":"line","text":"* 현재 활성 구독계정수(후불정산 변경안) — 최신 구독상태='구독' 회원수.\n*   위 subscribe.count(s.sub_state='구독' join count)와 동일 기준.","hangul_chars":35,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/migration/0001_default-organization.ts","lang":"js","line_start":11,"line_end":28,"block_type":"jsdoc","text":"task-688 — 기업↔기업상품 1:N 전환 백필 마이그레이션\n\n단계:\n 1) 기존 모든 agency에 대해 기본 조직(\"기본\"/DEFAULT) 1건 생성(이미 있으면 스킵).\n 2) tn_agency_contract.org_id 가 NULL 인 행을 해당 agency의 기본 조직으로 매핑.\n    - 동일 agency 내 다중 ACTIVE 계약이 존재하면 가장 최근(act_contract_ended_at 최대)만 ACTIVE 유지,\n      나머지는 EXPIRED 로 일괄 정리.\n 3) tn_member.org_id 가 NULL 인 행을 해당 agency의 기본 조직으로 매핑.\n\n멱등성:\n - 이미 매핑된(org_id != NULL) 행은 건드리지 않음.\n - 동일 (agcId, orgName='기본') 조직이 이미 존재하면 재사용.\n\n사용:\n - 배포 시 1회 호출 (예: nest 부트스트랩 단계에서 1회 또는 별도 CLI 진입점에서 실행).\n - NOT NULL ALTER 는 본 스크립트 완료 후 별도 DDL 단계에서 적용 권장.","hangul_chars":182,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/migration/0001_default-organization.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 1) 모든 agency 에 대해 기본 조직 보장","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/migration/0001_default-organization.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 2) NULL org_id 계약을 기본 조직으로 매핑","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/migration/0001_default-organization.ts","lang":"js","line_start":99,"line_end":100,"block_type":"line","text":"* 2-b) 동일 조직 내 ACTIVE 다중 계약을 정리(가장 최근 종료일 1건만 유지)\n*      drizzle update의 raw SQL 사용. MySQL 한정 문법.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/migration/0001_default-organization.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 3) NULL org_id 회원을 기본 조직으로 매핑","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization-admin.controller.ts","lang":"js","line_start":34,"line_end":39,"block_type":"jsdoc","text":"[관리자] 기업조직 관리 컨트롤러(task-688)\n- 응답 포맷은 컨트롤러 단위로 ApiResponseInterceptor를 적용해\n  { code, message, data } envelope으로 감싼다(기존 컨트롤러들과의 충돌 방지를 위해 전역 미적용).\n  따라서 컨트롤러는 data 페이로드만 반환한다.","hangul_chars":72,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization-admin.controller.ts","lang":"js","line_start":47,"line_end":48,"block_type":"line","text":"* 기업관리자(corp) 접근 검증(2026-07 기획 — 기업조직관리 화면): 최고관리자(SUPER)만,\n*  자기 기업(agcId) 조직만 허용. 조직관리자(ORG)와 타 기업 접근은 차단.","hangul_chars":48,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization-admin.controller.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* orgId 기반 엔드포인트용 — 대상 조직의 소속 기업을 조회해 corp 접근을 검증한다.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization-corp.controller.ts","lang":"js","line_start":23,"line_end":28,"block_type":"jsdoc","text":"[기업관리자] 기업조직 조회 전용 컨트롤러(task-688)\n- 기업 사용자는 자기 기업의 조직 목록 조회만 가능. 생성/수정/삭제는 admin/sales 전용.\n- agcId는 JWT payload(role='corp')에서 추출.\n- 응답 포맷은 컨트롤러 단위 ApiResponseInterceptor로 { code, message, data } envelope 적용.","hangul_chars":65,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization-corp.controller.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만 (최고관리자 SUPER는 전사)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":26,"line_end":30,"block_type":"jsdoc","text":"페이지네이션 표준(task-688)\n- page(1-base), size(default=20, max=500)\n- 응답은 items/total/page/size","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"* 목록 요청 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* 생성 요청 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* 조직트리(계층): 부모 조직 ID(ULID 26자). 미지정/null이면 루트로 생성.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* 엑셀 일괄 업로드의 조직 식별자 — 필수, 영문 대문자/숫자/하이픈/언더스코어만 허용.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":109,"line_end":109,"block_type":"line","text":"* 수정 요청 DTO (모든 필드 optional, 명시된 필드만 갱신)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 필수값 승격(엑셀 식별자) — 수정에서 미전송이면 기존 유지, 전송 시 비우기/null 불가.","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":142,"line_end":142,"block_type":"line","text":"* 상세응답: 조직 + 활성계약(요약) + 회원수","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":179,"line_end":179,"block_type":"line","text":"* 상세응답: 조직관리자(복수 가능) — 읽기 표시용. 지정/해제는 회원 상세의 조직·관리자 권한 탭에서.","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":227,"line_end":227,"block_type":"line","text":"* 목록 응답 DTO ({ items, total, page, size })","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":253,"line_end":253,"block_type":"line","text":"* 이동 요청 DTO — 대상 부모(null이면 루트로 이동)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":265,"line_end":265,"block_type":"line","text":"* 삭제 응답 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":277,"line_end":277,"block_type":"line","text":"* 하위 포함 삭제된 조직 수(응답 전용)","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.dto.ts","lang":"js","line_start":284,"line_end":284,"block_type":"line","text":"* 미배정(org_id=NULL)으로 전환된 소속 회원 수(응답 전용)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.entity.ts","lang":"js","line_start":13,"line_end":17,"block_type":"jsdoc","text":"기업조직 도메인 엔티티(task-688)\n- 기업↔기업상품 1:N 관계 도입에 따른 조직 단위 식별자.\n- orgId는 varchar(26) 문자열. 모든 ID는 string 직렬화 유지.","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.entity.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* 조직트리(계층): 부모 조직 ID(루트면 null). 프론트 트리 구성용.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.entity.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 조직트리(계층): 루트=0, 하위로 갈수록 +1.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.entity.ts","lang":"js","line_start":60,"line_end":61,"block_type":"line","text":"* 사전 확정 설계 계약(task-688)에 따라 외부 노출 키는 'description'으로 통일.\n* DB 컬럼명은 orgDescription을 유지하고, 응답/요청에서는 description으로 매핑.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.entity.ts","lang":"js","line_start":69,"line_end":70,"block_type":"line","text":"* 사전 확정 설계 계약(task-688)에 따라 외부 노출 키는 'useYn'으로 통일.\n* DB 컬럼명은 orgUseYn을 유지하고, 응답/요청에서는 useYn으로 매핑.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 계층 계산에 필요한 최소 노드 정보(생성/이동 시 부모·자신 전달용).","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":47,"line_end":48,"block_type":"line","text":"* 관리 org_path 하위(자신 포함) 전체 org_id — 부분트리 스코프 필터용.\n*   path가 '/{orgId}/' 형식이라 LIKE '{orgPath}%' 로 자신 + 모든 하위 매칭.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":58,"line_end":60,"block_type":"line","text":"* 조직 전체 경로 이름 일괄 계산 — { orgId: \"대구 > 개발팀\" }\n*   ⚠️ drizzle raw 상관 서브쿼리는 상관참조가 깨진 전례(회원수 폭증 버그)가 있어\n*   반드시 배치 조회(inArray) + JS 조합으로 계산한다.","hangul_chars":58,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"* (1) 중복 제거 + 빈 배열 가드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"* (2) 대상 org들의 orgId + orgPath 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* (3) 모든 path('/조상/.../자신/')를 split해 조상 orgId 전부 수집","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* (4) 조상 포함 전체 orgId → orgName 일괄 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":95,"line_end":95,"block_type":"line","text":"* (5) 각 요청 orgId에 대해 path 순서대로 이름을 ' > '로 join","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":110,"line_end":112,"block_type":"jsdoc","text":"조직 목록 조회 (페이지네이션 + 회원수/활성계약 보유여부 포함)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* orgPathScope: 조직관리자(ORG) 부분트리 스코프 — 지정 시 자기 org_path 하위(자신 포함)만 조회","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 조직트리(계층): 프론트 트리 구성용 parentId/depth 노출.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":136,"line_end":136,"block_type":"line","text":"* 외부 노출 키는 사전 확정 계약(task-688)에 따라 description/useYn으로 통일.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"* 조직트리 정렬 규칙: 조직명 오름차순(같으면 생성순) — 프론트 트리도 동일 규칙으로 형제 정렬.","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"* 회원수: 상관 서브쿼리가 상관참조가 깨져 전체를 세므로(폭증) org_id별 별도 집계 후 병합.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":185,"line_end":187,"block_type":"jsdoc","text":"단건 조회(상세) — 활성 계약 1건 + 회원수 포함","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":195,"line_end":195,"block_type":"line","text":"* 조직트리(계층): 프론트 트리 구성용 parentId/depth 노출.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"* 외부 노출 키는 사전 확정 계약(task-688)에 따라 description/useYn으로 통일.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"* 조직관리자(복수 가능) — 읽기 표시용. 지정/해제는 회원 상세에서.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":262,"line_end":264,"block_type":"jsdoc","text":"조직 단건 조회(검증용 — agcId 일치 확인 등에 사용)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":288,"line_end":290,"block_type":"jsdoc","text":"agcId 내 동일 orgName 존재 여부(자기 자신 제외)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":306,"line_end":308,"block_type":"jsdoc","text":"agcId 내 동일 orgCode 존재 여부(NULL 제외, 자기 자신 제외)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":324,"line_end":328,"block_type":"jsdoc","text":"조직 생성 — 계층(materialized path) 계산 포함.\n- 루트(parent=null): depth=0, path='/{orgId}/'\n- 하위: depth=부모depth+1, path=부모path+'{orgId}/'","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":335,"line_end":335,"block_type":"line","text":"* 부모 path는 백필로 항상 존재하지만, 방어적으로 null이면 '/{parentId}/'로 대체.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":354,"line_end":358,"block_type":"jsdoc","text":"노드 이동 — 자신 + 모든 하위의 org_path/org_depth 일괄 재계산(트랜잭션).\n- newParent=null 이면 루트로 이동.\n- 순환/기업일치 검증은 서비스에서 선행.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":375,"line_end":375,"block_type":"line","text":"* 자신 + 하위 일괄 재작성. SUBSTRING은 1-index라 prefixLen+1부터가 잔여 경로.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":383,"line_end":383,"block_type":"line","text":"* 이동 노드의 부모 포인터만 갱신(하위 부모관계는 불변).","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":391,"line_end":396,"block_type":"jsdoc","text":"노드 삭제 — 하위 노드까지 함께 하드 삭제(트랜잭션).\n- 소속 회원(tn_member.org_id)은 삭제하지 않고 org_id=NULL(미배정)로 전환.\n- 비활성 계약(FK restrict 회피)도 org_id=NULL 처리(활성 계약은 서비스가 사전 차단).\n- 자기참조 부모 FK 회피를 위해 삭제 전 org_parent_id 해제.","hangul_chars":76,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":434,"line_end":436,"block_type":"jsdoc","text":"주어진 조직 집합 중 활성 계약을 보유한 조직 존재 여부(부분트리 삭제 가드용).","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":453,"line_end":453,"block_type":"line","text":"* 명시된 필드만 갱신(undefined 필드는 변경하지 않음)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":468,"line_end":470,"block_type":"jsdoc","text":"Soft delete: useYn='N'로 비활성화","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":478,"line_end":480,"block_type":"jsdoc","text":"활성 회원 존재 여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.repository.ts","lang":"js","line_start":490,"line_end":492,"block_type":"jsdoc","text":"활성 계약 존재 여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":27,"line_end":30,"block_type":"jsdoc","text":"기업조직 서비스(task-688)\n- CRUD + 조직-기업 일치 검증 + 비활성화 가드(활성회원/활성계약).","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* orgPathScope: 조직관리자(ORG) 부분트리 스코프(자기 org_path 하위만)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":62,"line_end":64,"block_type":"jsdoc","text":"조직 생성 — 동일 agcId 내 orgName/orgCode 중복 차단(E0310).","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* 부모 지정 시: 존재 + 동일 기업 검증(다른 기업 하위로 생성 금지). 미지정이면 루트.","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":95,"line_end":95,"block_type":"line","text":"* 생성 직후 조회 실패 — 정상 경로에서는 발생하지 않음.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":101,"line_end":104,"block_type":"jsdoc","text":"조직 수정 — agcId 검증 + 이름/코드 중복 검증.\nagcId가 지정된 경우(컨트롤러에서 전달) 조직 소속 일치 여부 확인.","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":141,"line_end":143,"block_type":"jsdoc","text":"Soft delete — 활성 회원/계약 존재 시 차단.","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":168,"line_end":173,"block_type":"jsdoc","text":"노드 이동 — 자신 + 모든 하위 org_path/org_depth 일괄 재계산.\n- newParentId=null 이면 루트로 이동.\n- 순환 차단: 대상 부모가 자기 자신 또는 자기 하위면 400.\n- 같은 agcId 내에서만 이동 가능.","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":189,"line_end":189,"block_type":"line","text":"* 자기 자신으로 이동 금지.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":199,"line_end":199,"block_type":"line","text":"* 같은 기업 내에서만 이동 가능.","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":203,"line_end":203,"block_type":"line","text":"* 순환 차단: 대상 부모 path가 자신 path를 prefix로 가지면(=자기 하위) 금지.","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":226,"line_end":230,"block_type":"jsdoc","text":"노드 삭제 — 하위 노드까지 함께 삭제.\n- 소속 회원은 삭제하지 않고 org_id=NULL(미배정)로 전환.\n- 무결성 가드: 하위 포함 활성 계약 존재 시 삭제 차단(E0305).","hangul_chars":51,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":258,"line_end":262,"block_type":"jsdoc","text":"외부 모듈(계약/회원/agency-fc)에서 조직-기업 일치 검증에 사용.\n- org 미존재 → E0301\n- org.agcId !== 요청 agcId → E0302","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":278,"line_end":279,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 관리 org_path 하위(자신 포함) org_id 목록.\n*   각 도메인 WHERE 에 inArray(member.org_id, ids) 로 주입.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":284,"line_end":285,"block_type":"line","text":"* 조직 전체 경로 이름 일괄 계산 — { orgId: \"대구 > 개발팀\" }\n*   목록 화면 '소속조직' 컬럼(orgFullPath) 병합용.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":290,"line_end":291,"block_type":"line","text":"* 사용자 조직필터(orgId) → org_path LIKE prefix 변환.\n*   미존재 orgId면 어떤 행과도 매칭되지 않는 '/{orgId}/'를 반환해 자연히 빈 결과가 되게 한다.","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/organization/organization.service.ts","lang":"js","line_start":323,"line_end":323,"block_type":"line","text":"* 코드 중복도 같은 충돌 카테고리(E0310) 사용 — 설계 계약 기준.","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.controller.ts","lang":"js","line_start":49,"line_end":51,"block_type":"line","text":"* 기업관리자(corp) 정산 조회 가드 — 정산은 agcId 집계라 org 분해 불가.\n*   조직관리자(ORG)는 조회 불가(403), 최고관리자(SUPER)만 자기 기업 정산 조회.\n*   corp 가 아니면 null(=admin 통과).","hangul_chars":51,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.controller.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* corp(SUPER)는 자기 기업 정산만 + 정산확정 항목만 노출(2026-07 기획, company-mockup)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":214,"line_end":214,"block_type":"line","text":"* 정산 요약 (상세 — 실시간 집계)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":285,"line_end":285,"block_type":"line","text":"* 입금완료처리 — 유효 입금일 = paidAt ?? astPaidAt(구 admin 필드) ?? 오늘 (배포 과도기 겸용)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":295,"line_end":295,"block_type":"line","text":"* 구 admin 호환 필드 — 신 필드(paidAt) 미지정 시에만 사용","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":302,"line_end":302,"block_type":"line","text":"* 정산확정/해제 대상","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":310,"line_end":310,"block_type":"line","text":"* 주문 일괄 반영변경","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":325,"line_end":326,"block_type":"line","text":"* 주문 정산단가 일괄수정 — 전월 구독수 기준 단가 변동(예: 삼성 1.5만명 구간) 대응.\n*   tn_order.ord_settlement_price 를 일괄 갱신한다(결제금액 pmt_amount 는 불변).","hangul_chars":44,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":339,"line_end":339,"block_type":"line","text":"* 세금계산서 발행여부 수기 기록","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":353,"line_end":353,"block_type":"line","text":"* 정산 안내 메일 발송","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":373,"line_end":373,"block_type":"line","text":"* 일괄처리 skip 사유","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":384,"line_end":384,"block_type":"line","text":"* 일괄처리 결과 { processed, skipped }","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":408,"line_end":408,"block_type":"line","text":"* 소속조직 전체 경로 — 서비스에서 배치 병합(getOrgFullPathNames)한 값. 미배정이면 null","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":443,"line_end":443,"block_type":"line","text":"* stateForAgency() 변환 라벨 — 주문취소·실패 건도 목록에 포함됨","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.dto.ts","lang":"js","line_start":550,"line_end":550,"block_type":"line","text":"* 주문목록 검색조건 기준 합산","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 기업조직: 구독 주문내역 목록/엑셀 '소속조직'(orgFullPath) 병합용","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 소속조직 전체 경로 맵 — distinct orgId 배치 조회 { orgId: \"본부 > 1팀\" }","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":51,"line_end":52,"block_type":"jsdoc","text":"일괄처리 공통 골격 — astIds 현재 상태 조회 후 rule(사유 반환 시 skip)로 대상/제외 분리.\n 미존재 건은 공통 사유('정산 정보를 찾을 수 없습니다')로 skip.","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"기업 정산 목록조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":96,"line_end":96,"block_type":"jsdoc","text":"기업 정산 상세 — accountingEmail + 정산 요약(summary) 포함","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":103,"line_end":103,"block_type":"line","text":"* count 류는 settlement 블록의 라이브 집계를 재사용 — sums 에는 include 집계만 추가 선택됨","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"* 기업관리자(corp) 소유 검증 — 해당 정산(astId)이 corp 기업(agcId) 소속이 아니면 403.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":126,"line_end":126,"block_type":"jsdoc","text":"기업 정산 주문 목록 — 검색조건 기준 합산(aggregate) 포함","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"* 소속조직 전체 경로 병합 — 목록 '소속조직' 컬럼용(member.orgFullPath)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":157,"line_end":158,"block_type":"jsdoc","text":"기업 정산 구독내역 엑셀 다운로드 — isCorp면 기업관리자 상세 화면 컬럼과 완전 동일\n (분석사용수·분석예약수·소속조직·정산상태 제외, 2026-07 기획)","hangul_chars":53,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":166,"line_end":166,"block_type":"line","text":"* 소속조직 전체 경로 병합 — 엑셀 '소속조직' 컬럼용","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":172,"line_end":173,"block_type":"line","text":"* 기업관리자(corp)는 상세 화면 구독내역 컬럼 구성·순서와 완전 동일하게 —\n*  소속조직·분석사용수·분석예약수·정산상태 미노출","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":236,"line_end":238,"block_type":"jsdoc","text":"행별 정산상태 라벨(정산관리 상세/엑셀 공용) —\n 주문취소·실패 = 공란, CARRYOVER=정산이월, EXCLUDE=정산제외,\n INCLUDE는 정산확정 여부에 따라 정산확정/정산대기","hangul_chars":52,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":252,"line_end":253,"block_type":"jsdoc","text":"PENDING 정산의 주문 일괄변경 공통 검증 — 정산 존재/미확정, map 소속, 주문취소 skip.\n 반영변경·단가변경이 동일 규칙을 공유한다.","hangul_chars":44,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":271,"line_end":271,"block_type":"line","text":"* 대상 주문이 이 정산 map 에 속하는지 검증","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":285,"line_end":285,"block_type":"line","text":"* 주문취소 건은 변경 대상 아님 — skip 후 결과 안내","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":317,"line_end":322,"block_type":"jsdoc","text":"주문 정산단가 일괄수정 — PENDING 정산만, 주문취소 건 skip.\n전월 구독수 기준 단가 변동(예: 1.5만명 구간) 시 상세 주문내역 금액을 새 단가로 일괄 반영.\nord_settlement_price 만 갱신(결제금액 pmt_amount 불변) — 정산금액/확정금액 집계가\n이 값을 라이브로 합산하므로 수정 즉시 반영된다.","hangul_chars":92,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":341,"line_end":341,"block_type":"jsdoc","text":"정산확정 — PENDING 건만: CONFIRMED 전환 + INCLUDE 합 스냅샷. 이미 확정 건 skip","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":351,"line_end":352,"block_type":"line","text":"* 확정금액 스냅샷 = 현재 INCLUDE(결제완료) ord_settlement_price 합\n*   — astId IN 배치 집계 + UPDATE 를 단일 트랜잭션으로 처리 (부분 확정 방지)","hangul_chars":35,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":358,"line_end":358,"block_type":"jsdoc","text":"정산확정 해제 — CONFIRMED 건만: PENDING 전환 + 스냅샷 초기화. 미정산 건 skip","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":373,"line_end":373,"block_type":"jsdoc","text":"기업 정산 입금완료처리 — 유효 입금일 = paidAt ?? astPaidAt(구 admin) ?? 오늘, 이미 완료 건 skip","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":381,"line_end":381,"block_type":"line","text":"* 배포 과도기 겸용 — 신 admin(paidAt) 우선, 구 admin(astPaidAt) 수용, 둘 다 없으면 오늘(서버 로컬)","hangul_chars":24,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":394,"line_end":394,"block_type":"jsdoc","text":"기업 정산 입금철회처리 — 미완료 건 skip","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":410,"line_end":410,"block_type":"jsdoc","text":"세금계산서 발행여부 수기 기록 (실제 발행 API 연동은 범위 외) — 미존재 건 skip","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":426,"line_end":426,"block_type":"jsdoc","text":"구매내역서 PDF 생성 — CONFIRMED 정산만","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":438,"line_end":438,"block_type":"line","text":"* 품목 라인 — INCLUDE(결제완료) 주문을 상품명+단가별로 분리(목업 품목 분리 규칙)","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":446,"line_end":446,"block_type":"line","text":"* 금액은 확정 스냅샷(ast_confirmed_price, 반영분) 기준","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":463,"line_end":463,"block_type":"jsdoc","text":"정산 안내 메일 발송 — CONFIRMED 정산만, 발송 이력 기록","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":482,"line_end":482,"block_type":"line","text":"* 구매내역서 첨부 — PDF 생성 실패(폰트 미존재 등) 시 첨부 없이 발송하고 응답에 명시","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":504,"line_end":504,"block_type":"line","text":"* 본문은 텍스트 입력을 HTML 로 개행 변환 (기존 발송 템플릿과 동일하게 html 사용)","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-admin.service.ts","lang":"js","line_start":518,"line_end":518,"block_type":"line","text":"* 발송 이력 기록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"* 품목 라인 — 상품명+단가별 분리(동일 상품이라도 단가가 다르면 별도 행)","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":10,"line_end":10,"block_type":"jsdoc","text":"단가 (VAT 포함, ord_settlement_price)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":14,"line_end":14,"block_type":"jsdoc","text":"금액 (단가 × 주문수, VAT 포함)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":18,"line_end":18,"block_type":"line","text":"* 구매내역서 렌더링 데이터","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"정산코드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":22,"line_end":22,"block_type":"jsdoc","text":"정산연월 (YYYY-MM)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":24,"line_end":24,"block_type":"jsdoc","text":"정산확정일시","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":26,"line_end":26,"block_type":"jsdoc","text":"정산확정금액 (INCLUDE 스냅샷, VAT 포함)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":28,"line_end":28,"block_type":"jsdoc","text":"정산 반영(INCLUDE) 건수","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":30,"line_end":30,"block_type":"jsdoc","text":"품목 라인 (INCLUDE 주문의 상품명+단가별 집계)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":32,"line_end":32,"block_type":"jsdoc","text":"공급받는자(기업)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"* 공급자(자사) 정보 — insuniverse-site front/src/shared/ui/Footer.tsx 기준 (법인 정보 변경 시 함께 갱신)","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":51,"line_end":51,"block_type":"jsdoc","text":"금액 한글 표기 — 6,952,000 → '육백구십오만이천' (합계 문구 \"일금 ...원정\"용)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":79,"line_end":88,"block_type":"jsdoc","text":"구매내역서 PDF 빌더 (A4 · 기업 결재 제출용 요약 증빙)\n - 레이아웃은 planning/mockup/후불정산관리_구매내역서.html(admin) 기준:\n   제목+정산번호/발행일 → 공급자/공급받는자 박스 → 정산연월·반영건수 →\n   품목 테이블(품목/주문수/단가/공급가액/세액/금액, 상품·단가별 행 분리) →\n   합계(공급가액/세액/합계) → 한글 금액 문구 → 하단 확인 문구.\n - 금액은 정산확정금액(ast_confirmed_price, 반영분) 기준 — 미반영·이월 제외.\n - 단가 VAT 포함 정책: 공급가액 = 금액/1.1 반올림, 세액(VAT) = 금액 - 공급가액.\n - 한글 렌더링을 위해 인보이스와 동일한 S3 폰트(fonts/GmarketSansMedium.otf) 사용.","hangul_chars":177,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":98,"line_end":100,"block_type":"line","text":"* 폰트 바이트 메모이즈 — PDF 생성마다 S3 재다운로드 방지.\n*   Promise 자체를 캐시해 동시 호출도 단일 다운로드로 수렴, 실패 시 캐시 비워 다음 호출에서 재시도.\n*   (invoice 모듈 InvoiceStorageService.fetchFont 재사용은 도메인 간 모듈 의존이 생겨 로컬 메모이즈 선택)","hangul_chars":81,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"* 목업 품목 헤더색 #2a2e3f","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 목업 합계 문구 배경 #f7f8fb","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":158,"line_end":158,"block_type":"line","text":"* ===== 문서 헤더 — 제목(좌) + 정산번호·발행일(우) =====","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"* ===== 공급자 / 공급받는자 박스 =====","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":209,"line_end":209,"block_type":"line","text":"* ===== 메타 — 정산연월 · 정산 반영 건수 =====","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"* ===== 품목 테이블 — 품목 / 주문수 / 단가 / 공급가액 / 세액(VAT) / 금액 =====","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":255,"line_end":255,"block_type":"line","text":"* 페이지 넘침 가드 — 합계·문구 영역(하단 ~200pt) 확보 못 하면 다음 장에 헤더부터 재개","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":281,"line_end":281,"block_type":"line","text":"* ===== 합계 — 공급가액 / 세액(VAT 10%) / 합계 금액 (확정 스냅샷 기준) =====","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":304,"line_end":304,"block_type":"line","text":"* ===== 한글 금액 문구 =====","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":317,"line_end":317,"block_type":"line","text":"* 통화기호(₩)는 폰트 글리프 미보유 시 렌더 실패 위험이 있어 '원' 표기로 대체","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement-statement.builder.ts","lang":"js","line_start":324,"line_end":324,"block_type":"line","text":"* ===== 하단 확인 문구 =====","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.dto.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"* 이월 편입 주문 — 전월 정산에서 CARRYOVER 된 주문을 신규 정산 map에 INCLUDE로 편입","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.entity.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 정산상태(ast_settle_status)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.entity.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"* 주문별 정산반영(som_settle_action)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"* 정산수 = 결제완료 map 건수 (주문취소·실패 제외 — includePrice·getIncludeLineItems와 동일 모수)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 정산 반영금액 = INCLUDE & 결제완료 주문의 정산금액 합 (실시간)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":79,"line_end":80,"block_type":"line","text":"* 정산금액 = 결제완료 주문 전체(미반영·이월 포함)의 정산금액 합 (실시간).\n*   기획 정의 '항상 계산 표기' — 주문취소 시 즉시 반영(생성시점 스냅샷 astSettlementPrice 대체 표기용).","hangul_chars":59,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"* somSettleAction 별 건수 CASE 집계 — 결제완료 건만 (주문취소·실패 제외, includePrice와 동일 모수)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":101,"line_end":101,"block_type":"line","text":"* getList / getDetail 공용 settlement 선택 컬럼 (orderSums 라이브 집계 포함)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":121,"line_end":123,"block_type":"line","text":"* 정산금액 — 기획 정의 '항상 계산 표기': 결제완료 주문 전체 합(라이브).\n*   주문취소가 즉시 반영되도록 생성시점 스냅샷(ast_settlement_price) 대신 라이브 값을 노출한다.\n*   (map 이 비정상적으로 없는 건은 스냅샷 폴백)","hangul_chars":72,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 정산확정수 — 확정(CONFIRMED) 시 INCLUDE 건수, 미정산(PENDING)이면 null","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"* 기업관리자(corp) 소유 검증용 — astId 의 소속 기업(agcId)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":222,"line_end":222,"block_type":"line","text":"* 회계팀 이메일 — 해당 기업 최신 활성 계약의 act_accounting_email","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":227,"line_end":228,"block_type":"line","text":"* 정산 요약(summary) 조립용 — settlement 블록에 없는 실시간 집계만 추가 선택\n*   (settleCount/excludedCount/carryoverCount 는 settlement 블록 값을 재사용)","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":254,"line_end":255,"block_type":"line","text":"* 표시건수 선택 지원(단가/반영 일괄처리용) — 미지정 10, 상한 10,000\n*   (삼성 등 월 1.5만명 유입 대비 — 만건 표시 후 전체선택 일괄수정 시나리오)","hangul_chars":49,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":268,"line_end":268,"block_type":"line","text":"* 소속조직 — 목록 '소속조직' 컬럼용 (orgFullPath 는 서비스에서 배치 병합 후 member 에 주입)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":327,"line_end":327,"block_type":"jsdoc","text":"구독내역 엑셀용 전체 조회 (페이지네이션 없음)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":332,"line_end":332,"block_type":"line","text":"* 소속조직 — 엑셀 '소속조직' 컬럼용 (orgFullPath 는 서비스에서 배치 병합)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":345,"line_end":345,"block_type":"line","text":"* 엑셀 '주문상태' 컬럼 — 목록과 동일 라벨(주문완료/주문취소/주문실패)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":347,"line_end":347,"block_type":"line","text":"* 엑셀 '정산상태' 컬럼 — 반영 선택 + 정산확정 여부(라벨 조합은 서비스에서)","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":394,"line_end":394,"block_type":"line","text":"결제성공 주문건수 count","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":395,"line_end":395,"block_type":"line","text":"모든 주문건 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":407,"line_end":409,"block_type":"line","text":"* 편입 조건은 기획 정의(변경안)대로 '주문취소·실패 제외'만.\n*   사용건수(ord_used_qty) 조건은 기획에 없는 필터라 제거 — 분석 미사용 주문도\n*   정산에 편입해 상세에서 반영/미반영/이월로 처리한다(사용여부 필터로 식별 가능).","hangul_chars":81,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":411,"line_end":413,"block_type":"line","text":"* 정산 집계 가드(기획 §3.4) — 무상(FREE)·선불(PREPAID) 주문 제외를 '주문 스냅샷' 기준으로.\n*   기업 단위 제외는 과금방식 전환 기업의 과거 후불 주문까지 누락시켜 스냅샷으로 대체.\n*   IS NULL 허용은 백필 전 안전장치(백필 후 기업FC 주문은 전부 채워짐).","hangul_chars":84,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":440,"line_end":440,"block_type":"line","text":"* 신규 정산은 미정산(PENDING) — 컬럼 default와 동일하지만 의도 명시","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":445,"line_end":445,"block_type":"line","text":"* 당월 신규 주문 — 정산반영 default INCLUDE","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":452,"line_end":452,"block_type":"line","text":"* 이월 편입 주문 — 전월 CARRYOVER 건을 INCLUDE + 원 정산 id(som_carryover_from_ast_id)로 추가","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":455,"line_end":455,"block_type":"line","text":"* (astId, ordId) PK 중복 방지","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":471,"line_end":471,"block_type":"line","text":"* 이월 편입 대상 — 전월(YYYY-MM) 정산 map의 CARRYOVER 주문 목록","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":473,"line_end":473,"block_type":"line","text":"* astDate(DATE, 'YYYY-MM-DD') 함수 필터(DATE_FORMAT) 대신 sargable 범위 조건 — 인덱스 활용 가능","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":526,"line_end":526,"block_type":"line","text":"* 일괄처리 상태 판정용 — astIds 의 현재 상태 조회","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":540,"line_end":540,"block_type":"line","text":"* 반영변경 검증용 — 해당 정산 map 에 속한 주문 + 결제상태","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":559,"line_end":559,"block_type":"line","text":"* 주문 일괄 반영변경","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":577,"line_end":578,"block_type":"line","text":"* 주문 정산단가 일괄수정 — tn_order.ord_settlement_price 갱신(결제금액 pmt_amount 불변).\n*   정산 소속 검증(map)은 서비스에서 선행. 정산금액은 라이브 집계라 즉시 반영된다.","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":587,"line_end":589,"block_type":"line","text":"* 구매내역서 품목 라인 — INCLUDE(결제완료) 주문을 상품명+단가별로 분리 집계.\n*   기획(후불정산관리_구매내역서 목업): 구독상품이 다르면 행 분리, 동일 상품이라도\n*   단가가 다르면 별도 행(프로모션·차등 단가).","hangul_chars":77,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":615,"line_end":617,"block_type":"line","text":"* 정산확정 배치 — 상태/일시/처리자/확정금액 스냅샷.\n*   확정금액 집계(INCLUDE & 결제완료 합, astId IN 배치)와 UPDATE 를 단일 트랜잭션으로 묶어\n*   부분 확정·집계-UPDATE 사이 TOCTOU 를 제거.","hangul_chars":56,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":645,"line_end":645,"block_type":"line","text":"* map 에 주문이 없는 정산은 확정금액 0","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":653,"line_end":653,"block_type":"line","text":"* 정산확정 해제 — PENDING 전환, 스냅샷 초기화(재확정 시 갱신)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":667,"line_end":667,"block_type":"line","text":"* 세금계산서 발행여부 수기 기록","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":681,"line_end":681,"block_type":"line","text":"* 정산 안내 메일 발송 이력 기록","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":696,"line_end":696,"block_type":"line","text":"* 구매내역서용 정산+기업 기본정보","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":747,"line_end":747,"block_type":"line","text":"* 정산상태 필터 (PENDING/CONFIRMED)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":823,"line_end":824,"block_type":"line","text":"* 이 정산 map 에 속한 주문은 결제상태와 무관하게 목록에 포함 (주문취소 건도 노출)\n*   — 합산(getSettlementOrderAggregate)·확정 스냅샷은 각자 결제완료 조건으로 취소 제외","hangul_chars":53,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":827,"line_end":827,"block_type":"line","text":"* 정산반영 필터 (INCLUDE/EXCLUDE/CARRYOVER)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":834,"line_end":834,"block_type":"line","text":"* 사용여부 필터 — ord_used_qty 기준","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":841,"line_end":841,"block_type":"line","text":"* 텍스트 검색 — memLoginId(회원아이디) | subCode(구독번호) | ordCode(주문번호), LIKE %text%","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":867,"line_end":868,"block_type":"jsdoc","text":"주문목록 검색조건 기준 합산 — { count, totalPrice, includeCount, includePrice }\n 목록(where)은 주문취소 건 포함이지만, 합산·건수는 결제완료 건만 (취소 건 합산 제외)","hangul_chars":43,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.repository.ts","lang":"js","line_start":880,"line_end":880,"block_type":"line","text":"* tnSubscribe·tnMember 는 orderWhereClause 텍스트 검색(subNumber/memLoginId)에서 참조 — 유지","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.service.ts","lang":"js","line_start":10,"line_end":17,"block_type":"jsdoc","text":"월 정산 생성 (스케줄러 진입점)\n - 무상(FREE)·선불(PREPAID) 제외는 '주문 과금방식 스냅샷(ord_billing_type)' 기준(기획 §3.4) —\n   편입 쿼리(getAgencyFcOrderList) WHERE 가드로 처리. 과금방식 전환 기업의 과거 후불 주문도 정상 편입.\n - 이월 편입: 전월 정산 map의 CARRYOVER 주문을 신규 정산 map에\n   INCLUDE + som_carryover_from_ast_id(원 정산 id)로 추가하고 정산수/정산금액 집계에 포함.\n - 신규 정산 ast_settle_status='PENDING' (default).","hangul_chars":102,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.service.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* 전월 CARRYOVER 주문 — 신규 정산에 이월 편입","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.service.ts","lang":"js","line_start":43,"line_end":44,"block_type":"line","text":"* 이월 원 주문은 편입 가드를 통과한 후불(POSTPAID) 건 — 별도 무상 제외 불필요.\n* 당월 신규 주문이 없는 기업도 이월 건만으로 정산 생성","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/settlement/settlement.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 이월 건을 정산수/정산금액 집계에 포함 (드라이버가 집계값을 문자열로 줄 수 있어 Number 방어)","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.dto.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"* 공개 조회 쿼리 DTO (altCode / agcCode 둘 중 하나로 기업 해석)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.dto.ts","lang":"js","line_start":27,"line_end":28,"block_type":"line","text":"* 관리자 약관목록 조회 DTO (기업별 약관 관리)\n* agcId/약관명/노출여부는 모두 선택 검색조건. 미지정 시 전체 기업 약관 조회.","hangul_chars":44,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.dto.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"* 관리자 약관 신규등록 DTO","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.dto.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 관리자 약관 수정 DTO (기업 변경 불가)","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.entity.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 목록 표시용(조인). 상세조회에는 없을 수 있음.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.entity.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* 비인증 공개 동의 화면용 응답 엔티티 (프론트 계약: ctm* 접두)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.repository.ts","lang":"js","line_start":9,"line_end":9,"block_type":"line","text":"* 관리자 약관 목록 검색조건 (모두 선택값)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.repository.ts","lang":"js","line_start":22,"line_end":23,"block_type":"line","text":"* 공개 조회: 노출(agtEnabled=1) 약관만 정렬순서 오름차순으로 조회하며,\n* DB 컬럼(agt*)을 프론트 계약(ctm*)에 맞춰 별칭 프로젝션한다.","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.repository.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* 검색조건(agcId/약관명/노출여부)을 동적으로 조합. 미지정 조건은 무시.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.service.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"*--------------------------------- 공개 조회 ---------------------------------*/","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.service.ts","lang":"js","line_start":23,"line_end":24,"block_type":"line","text":"* 비인증 공개 동의 화면용 기업별 약관 조회.\n* 기업 해석에 실패해도 예외 없이 빈 목록을 반환한다(fail-safe).","hangul_chars":38,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.service.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"* altCode / agcCode 로 기업 id(agcId)를 해석한다. 해석 불가 시 undefined.","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.service.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"* 저장형 XSS 차단: 본문 HTML을 화이트리스트 기반으로 정제 후 저장","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/agency/terms/terms.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"* 저장형 XSS 차단: 본문 HTML을 화이트리스트 기반으로 정제 후 저장","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.entity.ts","lang":"js","line_start":56,"line_end":61,"block_type":"line","text":"@Expose()\n@ApiPropertyOptional({ description: '리다이렉트시 id' })\n@Transform(({ value }) => typeParser.int(value))\n@IsInt()\n@IsOptional()\nalmRedirectId?: number;","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.repository.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"알림 타입 필터 (SND001: 결제, SND002: 분석, SND003: 팩스, SND004: 이벤트)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 알람 저장시 FCM_TOKEN를 통한 firebase 앱 푸시 처리도 진행","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":63,"line_end":64,"block_type":"line","text":"* 알람 저장시 FCM 토큰도 발송되도록 조치\n* 멤버 테이블에서 FCM 토큰 + 푸시 알림 설정 조회","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":74,"line_end":75,"block_type":"line","text":"* 알림 타입별 동의 여부 확인\n* SND001: 결제(카드사용), SND002: 분석, SND003: 팩스(결제와 동일)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"팩스 (결제와 동일)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* FC 정보에 FCM_TOKEN이 있고 + 해당 알림 유형에 동의한 경우만 앱 푸시 발송","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* 상태값에 따른 주소 생성","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alarm/alarm.service.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"* firebase에 데이터 전송","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk-invite.spec.ts","lang":"js","line_start":85,"line_end":88,"block_type":"jsdoc","text":"초대링크 접근 유효성(validateInviteAccess) — 구독종료일/상태/건수/결제 기준.\nord_expired_at 미사용(구독 유효 고객 오차단 방지) 검증.","hangul_chars":38,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk-invite.spec.ts","lang":"js","line_start":150,"line_end":150,"block_type":"line","text":"* getDetail 결과에 ordExpiredAt이 과거여도 검사에 안 쓰이므로 통과해야","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.controller.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 진입 시점 만료 판별(구독종료/건수/탈퇴/기업차단) — 프론트가 즉시 '접근 기간 만료' 화면 노출","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":156,"line_end":160,"block_type":"jsdoc","text":"altMid의 값이 있고(없는경우 테스트모드 이거나 실패일경우)\naltRequestState가 [성공]이고\naltCompletionState의 값이 빈값인 경우","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"B2C 필터링: B2C 진료분석 성공/실패 알림톡 템플릿 코드로 필터링","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":217,"line_end":217,"block_type":"line","text":"정회원: B2C 템플릿 코드가 아닌 것들","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":221,"line_end":221,"block_type":"line","text":"기존 where 조건 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":226,"line_end":226,"block_type":"line","text":"B2C와 정회원의 select 필드가 다름","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"B2C: ordId에 bodId가 저장되어 있으므로 bodId로 B2C order_detail 조인","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":282,"line_end":282,"block_type":"line","text":"정회원: 기존 조인","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":311,"line_end":311,"block_type":"line","text":"B2C 필터링: B2C 진료분석 성공/실패 알림톡 템플릿 코드로 필터링","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":315,"line_end":315,"block_type":"line","text":"정회원: B2C 템플릿 코드가 아닌 것들","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":319,"line_end":319,"block_type":"line","text":"기존 where 조건 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.repository.ts","lang":"js","line_start":427,"line_end":427,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"jsdoc","text":"알림톡 목록","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":81,"line_end":81,"block_type":"jsdoc","text":"B2C 알림톡 목록","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"* 유효성검사추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 화면 모달은 우회 가능하므로 실제 발송 직전 서버에서 다시 차단한다.","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":178,"line_end":178,"block_type":"line","text":"* 결과값 저장","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":184,"line_end":189,"block_type":"jsdoc","text":"간편인증 인증확인 알림톡 발송\n간편인증(loginType='5') 요청 직후, 인증 대상자에게\n'본인 인증앱에서 인증을 확인해 주세요' 안내를 발송한다.\nordId는 정회원만 존재하므로 optional 처리한다.","hangul_chars":65,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"* 템플릿코드 미설정 시 발송 생략 (Aligo 템플릿 승인 후 환경변수로 주입)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":240,"line_end":240,"block_type":"line","text":"* 결과값 저장","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":247,"line_end":247,"block_type":"line","text":"* member 연락처 찾기","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":286,"line_end":286,"block_type":"line","text":"* 결과값 저장","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":343,"line_end":343,"block_type":"jsdoc","text":"머니 충전 완료 알림톡","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":351,"line_end":351,"block_type":"line","text":"중요: 알림톡 발송 전 최종 검증 - 회원 정보 확인","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":357,"line_end":357,"block_type":"line","text":"알림톡 발송 대상 정보 로깅 (디버깅용)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":360,"line_end":360,"block_type":"line","text":"전화번호가 없으면 알림톡 발송 불가","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":363,"line_end":363,"block_type":"line","text":"예외를 던지지 않고 조용히 종료 (결제는 성공 처리되어야 함)","hangul_chars":24,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":441,"line_end":441,"block_type":"line","text":"B2C는 bodId를 ordId에 저장","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":495,"line_end":495,"block_type":"line","text":"B2C는 bodId를 ordId에 저장","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":530,"line_end":530,"block_type":"line","text":"* altUsed는 1차 인증 성공 때 선점된다. 진행 중 링크 재진입은 SMS 화면 복구를 위해 허용.","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":573,"line_end":577,"block_type":"jsdoc","text":"@param ordId\n주문만료일이 지났거나, 사용가능횟수가 초과했을 경우\n결제실패/결제취소이거나 환불완료가 되었을 경우","hangul_chars":44,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":596,"line_end":604,"block_type":"jsdoc","text":"초대 알림톡 링크 \"클릭(분석 시작)\" 시점 접근 유효성 검사.\nvalidationOrder는 발송 시점에만 돌아, 발송 후 만료된 선발송 링크를 못 막는다 → certify 진입에서 호출.\n⚠️ 유효기간은 ord_expired_at이 아니라 **구독 이용종료일(subNextPayDay)**로 판정한다.\n   (ord_expired_at은 구독 갱신과 불일치해 구독 유효 고객을 오차단할 수 있음 — 실측 7천여 건.)\n   구독상태가 '해지'여도 이용종료일이 남아있으면 사용 가능하다(해지=종료일까지 이용 후 미갱신 의미).\n   따라서 해지 여부 자체는 차단 사유가 아니고, 이용종료일 경과만으로 막는다.\n차단 시 EXPIRED_ACCESS_LINK(E0214) → 프론트가 \"접근 기간 만료\" 화면 노출.","hangul_chars":192,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":611,"line_end":611,"block_type":"line","text":"* 구독 이용종료일 'YYYY-MM-DD'","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":614,"line_end":614,"block_type":"line","text":"* 구독 이용기간 종료(해지여도 종료일 전이면 사용 가능)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":616,"line_end":616,"block_type":"line","text":"* 분석건수 소진","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":617,"line_end":617,"block_type":"line","text":"* 결제 미완","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":619,"line_end":619,"block_type":"line","text":"* 회원 탈퇴(일반)/계정중지(기업) — 동일 컬럼","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":620,"line_end":620,"block_type":"line","text":"* 기업 접근차단(불량기업)","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":625,"line_end":628,"block_type":"jsdoc","text":"초대링크 접근 만료 여부(boolean) — 링크 진입 시점(checkAlimtalk)에서 throw 없이 판별용.\n프론트가 링크 클릭 즉시 '접근 기간 만료' 화면으로 보낼 수 있게 한다.","hangul_chars":50,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":647,"line_end":647,"block_type":"jsdoc","text":"알리고 발송완료여부 체크목록","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":652,"line_end":660,"block_type":"jsdoc","text":"알리고 발송완료여부 api 호출 및 상태 업데이트\n1. 알림톡 발송이 완료된 경우 : 상태업데이트\n2. 알림톡 발송중인 경우 : 리턴\n3. 알림톡 발송실패이고 대체문자가 발송된 경우\n 3-1. 대체문자 발송이 완료된 경우 : 상태업데이트\n 3-2. 대체문자 발송이 실패된 경우 : 상태업데이트\n 3-3. 대체문자 발송 중인 경우 : 리턴\n ※ msgid에 'Q'가 포함된 경우는 발송중","hangul_chars":124,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":662,"line_end":662,"block_type":"line","text":"* 알림톡 발송완료 여부 api","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":666,"line_end":666,"block_type":"line","text":"* 호출실패 또는 list가 없는 경우","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":673,"line_end":673,"block_type":"line","text":"* 1. 알림톡 발송이 완료된 경우 : 상태업데이트","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":690,"line_end":690,"block_type":"line","text":"* 2. 알림톡 발송중인 경우 : 리턴","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":697,"line_end":697,"block_type":"line","text":"* 3. 알림톡 발송실패이고 대체문자가 발송된 경우","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":702,"line_end":702,"block_type":"line","text":"* 대체문자 발송완료여부 확인 api","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":712,"line_end":712,"block_type":"line","text":"* 3-1,2. 대체문자 발송이 완료/실패된 경우 : 상태업데이트","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/alimtalk/alimtalk.service.ts","lang":"js","line_start":725,"line_end":725,"block_type":"line","text":"* 3-3. 대체문자 발송 중인 경우 : 리턴","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-admin-view.controller.ts","lang":"js","line_start":29,"line_end":34,"block_type":"jsdoc","text":"관리자 전용 일반회원 분석 API\n- 관리자가 iframe으로 분석 상세를 조회할 때 사용 (/admin-view/analyze/:oddId/*)\n- ★보안(C2): AdminViewTokenGuard로 scope(analyze)+oddId 스코프 단명 토큰(?t=) 검증. admin이 발급받아\n  iframe URL에 실어 전달. ADMIN_VIEW_TOKEN_ENFORCE='true' 시 차단 활성(그 전엔 경고 로그만=무중단).","hangul_chars":66,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-admin.controller.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* 기업관리자(corp) 스코프 검증 — 분석 상세가 자기 기업/조직 소속이 아니면 403.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-detail.entity.ts","lang":"js","line_start":44,"line_end":47,"block_type":"line","text":"@ApiProperty({ description: '분석대조한 투약' })\n@IsString()\n@IsOptional()\nasdDrug?: string;","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-detail.entity.ts","lang":"js","line_start":49,"line_end":52,"block_type":"line","text":"@ApiProperty({ description: '투약알릴사항' })\n@IsString()\n@IsOptional()\nasdDrugNotice?: string;","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-detail.entity.ts","lang":"js","line_start":54,"line_end":56,"block_type":"line","text":"@ApiProperty({ description: '방문일수' })\n@IsInt()\nasdVisitDays;","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-detail.entity.ts","lang":"js","line_start":58,"line_end":60,"block_type":"line","text":"@ApiProperty({ description: '조제정보 MAX ID' })\n@IsInt()\nasdDosingId;","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":82,"line_end":83,"block_type":"line","text":"------------------------- private -------------------------//\n\"약국\"이 포함된 병원명을 제외하는 조건 추가","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":91,"line_end":93,"block_type":"line","text":"if (!dto || !date) {\n  throw new Error('필수 파라미터 누락 (dto, date)');\n}","hangul_chars":8,"class":"1_policy","tags":["1_policy","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"3개월이내(내원, 수술, 검사, 투약, 기타)/유병자는 투약만 제외","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"1년이내 검사","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":116,"line_end":116,"block_type":"line","text":"5년이내 7일이상 치료 / 30일이상 투약일시엔 해당 basic이 상세가 됨","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"5년이내 입원/수술 (유병자의 경우 2년이내, 5년이내)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"ANS004 공통 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":144,"line_end":145,"block_type":"line","text":"5년이내 11(6)대 질병 진단, 수술\nANS003과 조건이 동일하지만 조건이 변경될 수 있으니 따로 구성함","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"숨은보험(진단), 약국포함, 기본진단","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":163,"line_end":163,"block_type":"line","text":"숨은보험(치아) 기본진단 and 상세치료","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":171,"line_end":171,"block_type":"line","text":"숨은보험(수술) 상세치료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"숨은보험(기타) 상세치료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":186,"line_end":186,"block_type":"line","text":"치아고지(틀니) 기본진단 or 상세치료","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":192,"line_end":192,"block_type":"line","text":"치아고지(1년) 기본진단 and 상세치료","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":202,"line_end":202,"block_type":"line","text":"치아고지(5년) 기본진단 and 상세치료","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":210,"line_end":210,"block_type":"line","text":"주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":234,"line_end":235,"block_type":"line","text":"수술, 검사, 투약만\n투약은 다른 수술/검사가 있을 경우 투약항목에 포함 됨","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"1년이내 검사","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":249,"line_end":249,"block_type":"line","text":"5년이내 입원/수술","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":255,"line_end":255,"block_type":"line","text":"숨은보험(치아)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"숨은보험(수술)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":265,"line_end":265,"block_type":"line","text":"숨은보험(기타)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":270,"line_end":270,"block_type":"line","text":"치아고지(틀니)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"치아고지(1년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"치아고지(5년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":289,"line_end":290,"block_type":"line","text":"------------------------- ansType별 공통 조건 -------------------------//\nANS002: 1년이내 검사","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":296,"line_end":296,"block_type":"line","text":"ANS007: 숨은보험(치아)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":302,"line_end":302,"block_type":"line","text":"ANS008: 숨은보험(수술)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":308,"line_end":308,"block_type":"line","text":"ANS009: 숨은보험(기타)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":314,"line_end":314,"block_type":"line","text":"ANS010: 치아고지(틀니)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":320,"line_end":320,"block_type":"line","text":"ANS011: 치아고지 (1년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":326,"line_end":326,"block_type":"line","text":"ANS012: 치아고지 (5년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":409,"line_end":409,"block_type":"line","text":"수술, 검사, 투약만","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":418,"line_end":418,"block_type":"line","text":"1년이내 검사","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":423,"line_end":423,"block_type":"line","text":"5년이내 입원/수술","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":429,"line_end":429,"block_type":"line","text":"숨은보험(치아)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":434,"line_end":434,"block_type":"line","text":"숨은보험(수술)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":439,"line_end":439,"block_type":"line","text":"숨은보험(기타)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":444,"line_end":444,"block_type":"line","text":"치아고지(틀니)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":449,"line_end":449,"block_type":"line","text":"치아고지(1개)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze-where.builder.ts","lang":"js","line_start":454,"line_end":454,"block_type":"line","text":"치아고지(5개)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* oddId만 바꿔 남의 분석(고객 개인정보·진료이력)을 조회할 수 있어 소유자 검증을 추가한다.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":262,"line_end":262,"block_type":"line","text":"B2C 전용 컨트롤러 (인증 없음)","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":349,"line_end":350,"block_type":"line","text":"isB2c = true\nB2C는 bab*, bad*, bcb* prefix를 사용하므로 DTO 변환 없이 그대로 반환","hangul_chars":16,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":446,"line_end":446,"block_type":"line","text":"B2C 주문 및 사용자 정보 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":454,"line_end":454,"block_type":"line","text":"자동차보험 데이터 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":457,"line_end":457,"block_type":"line","text":"count 계산 (전체 데이터 조회)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":538,"line_end":538,"block_type":"line","text":"먼저 생년월일 검증","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":545,"line_end":545,"block_type":"line","text":"생년월일이 맞으면 조회 기간 체크 (분석요청일로부터 1년)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":561,"line_end":561,"block_type":"line","text":"인증 성공 시 쿠키에 저장 (7일간 유효)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":592,"line_end":592,"block_type":"line","text":"상담신청 상태 및 조회 기간 확인","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":596,"line_end":596,"block_type":"line","text":"조회 기간 만료 체크 (생성일로부터 1년)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.controller.ts","lang":"js","line_start":647,"line_end":647,"block_type":"line","text":"B2C 사용자 및 추가 API","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 자동차 보험","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":353,"line_end":353,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API 머지 항목 (ANS001 전용)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":497,"line_end":497,"block_type":"line","text":"* 자동차 보험 Response","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":545,"line_end":545,"block_type":"line","text":"* PDF처리를 위한 분석데이터(숨은보험금) 탭별 전체 처리","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":664,"line_end":664,"block_type":"line","text":"==================== 병명예측 PDF 데이터 ====================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":666,"line_end":666,"block_type":"line","text":"병명기준 추천보험/보험참고 - 항목","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":685,"line_end":685,"block_type":"line","text":"병명기준 추천보험/보험참고 - 대분류","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":702,"line_end":702,"block_type":"line","text":"==================== 진단로그 트리 구조 DTO (중분류 기준) ====================","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":704,"line_end":704,"block_type":"line","text":"세세세분류 DTO","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":723,"line_end":723,"block_type":"line","text":"세세분류 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":798,"line_end":798,"block_type":"line","text":"중분류 DTO (최상위)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":823,"line_end":823,"block_type":"line","text":"검사기준 - 항목","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":834,"line_end":834,"block_type":"line","text":"검사기준 - 카테고리","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":851,"line_end":851,"block_type":"line","text":"투약기준 - 항목","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":866,"line_end":866,"block_type":"line","text":"투약기준 - 카테고리","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":883,"line_end":883,"block_type":"line","text":"진료로그 항목 DTO","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":926,"line_end":926,"block_type":"line","text":"병명예측 PDF 데이터 응답","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.dto.ts","lang":"js","line_start":979,"line_end":979,"block_type":"line","text":"B2C 생년월일 인증 DTO","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"* 약국의 경우 투약일수를 정확하게 매칭이 가능하므로, 약국일 경우엔 asdDosingDays로 병원은 asbDosingDays","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 분석상세의 각 항목에 대한 1건 도출","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":134,"line_end":134,"block_type":"line","text":"* 분석상세의 각 항목에 대한 상세 수량","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"* count가 groupBy로 묶이므로 groupBy가 있는 곳은 length로 가져올 것","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":239,"line_end":246,"block_type":"jsdoc","text":"(ANS003) 5년내 7일이상 진료, 30일이상 투약\n(ANS005) 5년내 질병, 진단\n(ANS006) 숨은보험 진단\n@param id\n@param dto\n@returns","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"* 숨은보험진단(ANS006), 보상찾아줘-기타(ANS009)의 경우만 약국도 포함","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":261,"line_end":261,"block_type":"line","text":"* ANS009(보상찾아줘-기타)일 경우 asdInEtc별로 행을 분리해야 하므로 GROUP BY에 포함","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":279,"line_end":279,"block_type":"line","text":"투약중복여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"상세의 요약 1건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":282,"line_end":282,"block_type":"line","text":"ANS009: GROUP BY에 포함하므로 MAX 불필요","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":283,"line_end":283,"block_type":"line","text":"기타: 숨은보험 기타","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":299,"line_end":302,"block_type":"jsdoc","text":"2차쿼리 조건절\nANS003일 경우 외래만 가져오는 것으로 조건 추가됨","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":335,"line_end":341,"block_type":"jsdoc","text":"최종 쿼리의 조건절\nANS003일 경우 7일이상 치료 또는 30일이상 투약의 건\nANS006(숨은보험진단)의 건강체일 경우, 질병에 해당하는 건\nANS013(주의사항)일 경우 주의사항 해당하는 건\nANS005의 유병자일 경우, 유병자질병에 해당하는 건","hangul_chars":80,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":433,"line_end":434,"block_type":"line","text":"약품명 ↔ 투약기준(병명예측관리 투약로그) 대조로 효능효과 조회\nmscCode 중복 등록 시 행 증식을 막기 위해 상관 서브쿼리로 단일 값만 반환","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":472,"line_end":472,"block_type":"line","text":"* 자동차 보험 추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":579,"line_end":580,"block_type":"line","text":"------------------------- schedule -------------------------//\n* 스케줄러를 통한 30일 경과시 분석결과 데이터 삭제(기본, 상세, 자동차진료기본, 자동차진료상세)","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":585,"line_end":585,"block_type":"line","text":"* 생성된지 30일이 지난 주문상세건 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":593,"line_end":593,"block_type":"line","text":"* id값만 추출해 number 배열 생성","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":596,"line_end":597,"block_type":"line","text":"* 주문 id 기준으로 분석결과 정보 삭제\n* 삭제된 주문 상세건의 연결된 user_id 정보도 null 처리","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":632,"line_end":632,"block_type":"line","text":"* 생성된지 30일이 지난 B2C 주문상세건 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":643,"line_end":643,"block_type":"line","text":"* 주문 id 기준으로 B2C 분석결과 정보 삭제","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":707,"line_end":707,"block_type":"line","text":"WHERE 조건 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":713,"line_end":713,"block_type":"line","text":"ANS004는 특별 처리: 입원 OR 수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":727,"line_end":727,"block_type":"line","text":"detail 필터 조건을 서브쿼리로 추가 (페이지네이션 전에 필터링)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":743,"line_end":743,"block_type":"line","text":"정회원과 동일한 방식으로 LEFT JOIN + GROUP BY로 한 번에 조회","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":840,"line_end":840,"block_type":"line","text":"WHERE 조건 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":846,"line_end":846,"block_type":"line","text":"ANS004는 특별 처리: 입원 OR 수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":860,"line_end":860,"block_type":"line","text":"detail 필터 조건 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":862,"line_end":862,"block_type":"line","text":"detailFilterField가 이미 완전한 조건인 경우(ANS001 등)와 단일 필드인 경우 모두 처리","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":877,"line_end":877,"block_type":"line","text":"groupBy 결과의 개수 반환","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":931,"line_end":931,"block_type":"line","text":"인증요청중","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":950,"line_end":950,"block_type":"line","text":"분석 완료 시 bod_exposed를 1로 설정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1074,"line_end":1074,"block_type":"line","text":"B2C 생년월일 검증","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1086,"line_end":1086,"block_type":"line","text":"생년월일 비교 (암호화된 데이터를 복호화한 값과 비교)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1095,"line_end":1095,"block_type":"line","text":"* 숨은보험진단(ANS006), 보상찾아줘-기타(ANS009)의 경우만 약국도 포함","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1104,"line_end":1104,"block_type":"line","text":"* ANS009(보상찾아줘-기타)일 경우 basdInEtc별로 행을 분리해야 하므로 GROUP BY에 포함","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1186,"line_end":1186,"block_type":"line","text":"질병코드 필터링 추가","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1270,"line_end":1271,"block_type":"line","text":"약품명 ↔ 투약기준(병명예측관리 투약로그) 대조로 효능효과 조회\nmscCode 중복 등록 시 행 증식을 막기 위해 상관 서브쿼리로 단일 값만 반환","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1480,"line_end":1482,"block_type":"jsdoc","text":"B2C 상담신청 상태 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1607,"line_end":1610,"block_type":"line","text":"bodAssigned는 아직 컬럼이 없으므로 TODO\nif (bodAssigned !== undefined && bodAssigned !== null) {\n  where.push(eq(tnB2cOrderDetail.bodAssigned, bodAssigned));\n}","hangul_chars":10,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1656,"line_end":1656,"block_type":"line","text":"TODO: 담당회원아이디 검색 (컬럼 추가 후)","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1746,"line_end":1747,"block_type":"line","text":"* 정회원 — 심평원 '내가 먹는약 한눈에' 신규 데이터 중 기존 기본진료정보(ttTreatBasic)에 없는 건만 반환\n* ANS001([baseDate-3개월, baseDate]) 영역에서 사용","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1771,"line_end":1773,"block_type":"line","text":"* 기존 기본진료정보(ttTreatBasic)에 동일 진료일+병원명 조합이 없는 건만 선택\n* 병원/약국명 양쪽이 모두 NULL인 행은 SQL 3-value logic상 매칭이 항상 UNKNOWN이 되므로,\n* basic 측이 NULL이고 medicine 측도 NULL이면 동일 진료일 기준으로 매칭된 것으로 간주","hangul_chars":74,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1793,"line_end":1793,"block_type":"line","text":"* B2C — 심평원 '내가 먹는약 한눈에' 신규 데이터 중 기존 기본진료정보에 없는 건만 반환","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1819,"line_end":1819,"block_type":"line","text":"* 병원/약국명 양쪽이 모두 NULL이면 동일 진료일 기준으로 매칭된 것으로 간주 (NULL-safe)","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1839,"line_end":1841,"block_type":"line","text":"============================================================================\n기업관리자(corp) 접근제어 — 분석 상세(oddId/asbId/acbId)의 소속 기업/조직 검증\n============================================================================","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1843,"line_end":1844,"block_type":"line","text":"* oddId 가 corp 스코프(자기 기업 agcId + ORG는 org_path 부분트리) 안에 있는지 여부.\n*   join 경로: order_detail → order → payment → subscribe → member → org","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1873,"line_end":1873,"block_type":"line","text":"* asbId(분석기본) → oddId 해석","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1883,"line_end":1883,"block_type":"line","text":"* acbId(자동차보험 분석기본) → oddId 해석","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1893,"line_end":1893,"block_type":"line","text":"* basbId(B2C 분석기본) → bodId 해석","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1903,"line_end":1903,"block_type":"line","text":"* bcbId(B2C 자동차보험 분석기본; 실제 테이블 키 bacbId) → bodId 해석","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1913,"line_end":1913,"block_type":"line","text":"* casbId(고객사 분석기본) → codId 해석","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.repository.ts","lang":"js","line_start":1923,"line_end":1923,"block_type":"line","text":"* cacbId(고객사 자동차보험 분석기본) → codId 해석","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":49,"line_end":50,"block_type":"line","text":"* 기업관리자(corp) 접근제어 — 분석 상세가 자기 기업/조직 소속인지 검증. 아니면 403.\n*   scope = { agcId, orgPath? }. by 로 asbId/acbId 를 oddId 로 해석 후 검증.","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"*분석결과기본","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"B2C는 bodId를 oddId로 받음","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"정회원과 동일하게 무조건 getBasicList 사용","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* ANS001(3개월 내) — 심평원 '내가 먹는약 한눈에' 신규 데이터 머지","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":148,"line_end":148,"block_type":"line","text":"정규 회원인 경우","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":158,"line_end":158,"block_type":"line","text":"* ANS001(3개월 내) — 심평원 '내가 먹는약 한눈에' 신규 데이터 머지","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 신규 데이터 조회 (기존 기본진료정보에 없는 최신 건만)","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"* ANS001 기준 [baseDate-3개월, baseDate] 윈도우. 동기화 시차로 baseDate 이후 일자가 섞이는 케이스를 방지하기 위해 상한도 적용.","hangul_chars":36,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":202,"line_end":202,"block_type":"line","text":"* 처방기관","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":204,"line_end":204,"block_type":"line","text":"* 조제기관","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"*분석결과상세","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"* 분석기본정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":234,"line_end":235,"block_type":"line","text":"* 5년내 7일이상 진료/30일이상 투약 기본\n* 11(6)대 질병진단/수술 기본","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":293,"line_end":293,"block_type":"line","text":"* 처방조제정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":303,"line_end":303,"block_type":"line","text":"B2C basicList 조회 - 해당 날짜의 진료 기본 정보","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"* 원본데이터 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":335,"line_end":335,"block_type":"line","text":"TODO ExcelService로 추후 빼기","hangul_chars":5,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":392,"line_end":392,"block_type":"line","text":"* 분석결과기본(자동차보험)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":427,"line_end":427,"block_type":"line","text":"* 분석결과상세(자동차보험)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":454,"line_end":454,"block_type":"line","text":"* 분석결과 숨은 보험금 전체 목록(PDF 다운로드용)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":460,"line_end":460,"block_type":"line","text":"B2C 주문 정보 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":467,"line_end":467,"block_type":"line","text":"* 숨은보험금 진단 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":474,"line_end":474,"block_type":"line","text":"* 숨은보험금 수술 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":488,"line_end":488,"block_type":"line","text":"* 숨은보험금 치아","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":502,"line_end":502,"block_type":"line","text":"* 숨은보험금 기타","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":557,"line_end":557,"block_type":"line","text":"* 사용자/B2C PDF 묶음에는 내부 카나리 자동차 자료를 절대 포함하지 않는다.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":565,"line_end":565,"block_type":"line","text":"* 숨은보험금 진단 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":572,"line_end":572,"block_type":"line","text":"* 숨은보험금 수술 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":584,"line_end":584,"block_type":"line","text":"* 숨은보험금 치아","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":596,"line_end":596,"block_type":"line","text":"* 숨은보험금 기타","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":648,"line_end":648,"block_type":"line","text":"* 일반회원 PDF 묶음에도 자동차 자료를 노출하지 않는다.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":653,"line_end":653,"block_type":"line","text":"* 분석결과 주의사항 전체 목록(PDF 다운로드용)","hangul_chars":17,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":699,"line_end":699,"block_type":"line","text":"* 분석결과 건강체 전체 목록(PDF 다운로드용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":724,"line_end":724,"block_type":"line","text":"ANS002: 1년 내 검사","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":738,"line_end":738,"block_type":"line","text":"ANS003: 5년 내 7일/30일 투약 (aggregate)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":746,"line_end":746,"block_type":"line","text":"ANS004: 5년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":760,"line_end":760,"block_type":"line","text":"ANS005: 5년 내 11대 중대질병 (aggregate, asbSicked=0)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":788,"line_end":788,"block_type":"line","text":"ANS002: 1년 내 검사","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":796,"line_end":796,"block_type":"line","text":"ANS003: 5년 내 7일/30일 투약 (aggregate)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":806,"line_end":806,"block_type":"line","text":"ANS004: 5년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":814,"line_end":814,"block_type":"line","text":"ANS005: 5년 내 11대 중대질병 (aggregate, asbSicked=0)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":833,"line_end":833,"block_type":"line","text":"* 분석결과 유병자 전체 목록(PDF 다운로드용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":858,"line_end":858,"block_type":"line","text":"ANS004_2: 2년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":872,"line_end":872,"block_type":"line","text":"ANS004_5: 5년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":886,"line_end":886,"block_type":"line","text":"ANS005: 5년 내 6대 중대질병 (aggregate, asbSicked=1)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":913,"line_end":913,"block_type":"line","text":"ANS004_2: 2년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":921,"line_end":921,"block_type":"line","text":"ANS004_5: 5년 내 입원/수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":929,"line_end":929,"block_type":"line","text":"ANS005: 5년 내 6대 중대질병 (aggregate, asbSicked=1)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1070,"line_end":1070,"block_type":"line","text":"* 5년 내 7일이상 진료 그룹 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1086,"line_end":1086,"block_type":"line","text":"* 5년 내 30일이상 투약 그룹 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1102,"line_end":1102,"block_type":"line","text":"* 기타 숨은보험금 그룹 조회 (ANS009)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1107,"line_end":1107,"block_type":"line","text":"* 동일 진단코드 내원 그룹 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1123,"line_end":1123,"block_type":"line","text":"* 치아 숨은보험금 그룹 조회 (ANS007)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1137,"line_end":1137,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1178,"line_end":1178,"block_type":"line","text":"* 자동차 보험 추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1193,"line_end":1193,"block_type":"line","text":"* 자동차 보험(상세) 추가","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1219,"line_end":1221,"block_type":"line","text":"* 기본정보는 basic 테이블 PK 로 조회한다.\n* (searchId() 는 basic↔detail 좌조인의 detail 컬럼을 필터하므로\n*  detail 이 없는 basic 이 통째로 누락되어 500 이 발생했다.)","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1264,"line_end":1264,"block_type":"line","text":"*------------------------ 병명예측 PDF 데이터 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1266,"line_end":1266,"block_type":"line","text":"* 기업코드는 변경될 수 있으므로 환경별 불변 agcId로만 임시 마스킹한다.","hangul_chars":27,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1285,"line_end":1285,"block_type":"line","text":"B2C는 bodId로 전달","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1291,"line_end":1291,"block_type":"line","text":"B2C는 bodId로 전달","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1311,"line_end":1311,"block_type":"line","text":"B2C WHERE 조건 생성 헬퍼 메서드 (정회원 AnalyzeWhereBuilder와 동일한 로직)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1324,"line_end":1326,"block_type":"line","text":"* ★보안(C3 SQLi): asbDiseaseCode가 baseCondition에 문자열 보간되고 하류에서 sql.raw로 실행되므로\n*   인젝션 표면(특히 비인증 admin-view 경로로 도달). 상병코드(KCD)는 영숫자·점·하이픈만 가지므로\n*   그 외 문자가 있으면 거부 → 따옴표/세미콜론/공백 주입 불가. (정상 코드는 전부 통과)","hangul_chars":85,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1333,"line_end":1333,"block_type":"line","text":"3개월 이내 (정회원과 동일: 약국제외 없음, sicked 조건 없음)","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1338,"line_end":1338,"block_type":"line","text":"1년 이내 검사 + 약국제외 (정회원과 동일: sicked 조건 없음)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1343,"line_end":1343,"block_type":"line","text":"diseaseCode 필수 + 외래 + 약국제외","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1350,"line_end":1351,"block_type":"line","text":"searchYear 필수 + 약국제외 (입원/수술 조건은 repository에서 처리)\n정회원: searchYear가 2면 730일, 아니면 날짜 조건 없음","hangul_chars":32,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1360,"line_end":1360,"block_type":"line","text":"diseaseCode 필수 + 약국제외 (정회원과 동일: 날짜 조건 없음)","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1367,"line_end":1367,"block_type":"line","text":"diseaseCode 필수 + inDisease (약국 포함)","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1374,"line_end":1374,"block_type":"line","text":"inTooth=1 + 약국제외 (정회원과 동일: 날짜 조건 없음)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1378,"line_end":1378,"block_type":"line","text":"약국제외 (정회원과 동일: 날짜 조건 없음, detail 필터는 repository에서)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1382,"line_end":1382,"block_type":"line","text":"약국제외 (정회원과 동일: 날짜 조건 없음, detail 필터는 repository에서)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1388,"line_end":1388,"block_type":"line","text":"dentures + 약국제외 (정회원과 동일: 날짜 조건 없음)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1392,"line_end":1392,"block_type":"line","text":"1년 이내 + toothOne + 약국제외","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1397,"line_end":1397,"block_type":"line","text":"toothFive + 약국제외 (정회원과 동일: 날짜 조건 없음)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1401,"line_end":1401,"block_type":"line","text":"diseaseCode 필수 + notice + 약국제외","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1408,"line_end":1408,"block_type":"line","text":"ANS014 등: 조건 없음 (정회원과 동일: switch에 case 없으면 조건 추가 안 함)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1419,"line_end":1419,"block_type":"line","text":"3개월내 수술/검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1421,"line_end":1421,"block_type":"line","text":"1년내 검사","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1423,"line_end":1423,"block_type":"line","text":"숨은보험-치아","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1425,"line_end":1425,"block_type":"line","text":"숨은보험-수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1427,"line_end":1427,"block_type":"line","text":"숨은보험-기타","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1429,"line_end":1429,"block_type":"line","text":"Basic 테이블만 체크","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1439,"line_end":1439,"block_type":"line","text":"* B2C 자동차보험 상세 (정회원과 동일하게 bcbId로만 조회)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1455,"line_end":1455,"block_type":"line","text":"* B2C 진단 상세 (정회원과 동일한 로직으로 처리)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1457,"line_end":1457,"block_type":"line","text":"* 분석기본정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1461,"line_end":1461,"block_type":"line","text":"* 상세정보 (ansType에 따른 필터링 적용)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/analyze/analyze.service.ts","lang":"js","line_start":1482,"line_end":1484,"block_type":"jsdoc","text":"B2C 상담신청 상태 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/admin-optional.guard.ts","lang":"js","line_start":6,"line_end":21,"block_type":"jsdoc","text":"관리자 신원 비차단 복원 가드.\n\n회원 화면과 관리자 admin-view(iframe)가 공유하는 공개 조회 경로에서 관리자 신원을\n복원한다. 없거나 무효여도 요청을 차단하지 않는다 — 차단 여부는 서비스의 소유자\n검증(assertOddOwner + isAdminViewerAllowed)이 결정한다.\n\n두 가지 경로:\n1) admin JWT(_aaT 쿠키) — admin 패널과 API가 쿠키를 공유하는 환경.\n2) admin-view 단명 토큰(x-admin-view-token 헤더 또는 ?t) — iframe 요청에 쿠키가\n   실리지 않는 환경(로컬 admin ↔ stg 사이트 등). scope 'analyze'+query.oddId로\n   서명·TTL을 검증하며, 발급 시 이미 관리자 인증 + corp 기업 스코프가 검증된 토큰이다.\n\n회원 토큰({ id, type, memId })에는 role 클레임이 없으므로 _aaT에 회원 토큰을 넣어도\n관리자로 오인되지 않는다(서비스 판정이 role 기반).","hangul_chars":199,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/admin-optional.guard.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 관리자 토큰 아님/만료 — 회원 인증 경로로 계속 진행","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/allow-org-write.decorator.ts","lang":"js","line_start":3,"line_end":4,"block_type":"line","text":"* CorpReadonlyGuard 예외 — 조직관리자(CORP_ORG)에게 쓰기를 허용할 핸들러에 부착.\n*   핸들러 내부 서비스에서 agcId/orgPath 부분트리 스코프를 반드시 검증해야 한다.","hangul_chars":48,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.controller.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"cross-origin 허용 (로컬 개발 환경 지원)","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.controller.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 영업대리점 로그인","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.controller.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"cross-origin 허용 (로컬 개발 환경 지원)","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.controller.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"* 기업관리자 로그인","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.controller.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"* 조직관리자 로그인 (tn_member 기반 CORP_ORG, 자기 부분트리 운영 가능)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"기업관리자 로그인 요청 DTO","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"조직관리자 로그인 DTO (tn_member 기반)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":52,"line_end":53,"block_type":"line","text":"* 기획(2026-07, 로그인_기업조직관리자.html): 기업 식별을 로그인 아이디가 아닌\n*  공개용 기업코드(agcCorporateCode)로 변경 — 조직관리자가 최고관리자 아이디를 몰라도 됨","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"기업관리자 정보 DTO","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 권한: CORP_SUPER(최고관리자) / CORP_ORG(조직관리자). CORP_ORG 운영 가능 여부는 orgCanWrite로 분리.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.dto.ts","lang":"js","line_start":105,"line_end":105,"block_type":"line","text":"기업관리자 로그인 응답 DTO","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 영업대리점 로그인","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"* 기업관리자 로그인","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"* 기존 corp 계정 = 최고관리자(전사 범위, 수정 가능). 조직 스코프 없음(orgPath=null).","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":138,"line_end":139,"block_type":"line","text":"* 조직관리자 로그인 — tn_member(MEM002 + mem_is_org_manager=1) 기반, 자기 org 부분트리 스코프.\n* 기업 식별은 공개용 기업코드(agcCorporateCode) 기준 (2026-07 기획 — 로그인 입력값 변경)","hangul_chars":43,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":153,"line_end":154,"block_type":"line","text":"* 조직관리자는 자기 부분트리(orgPath) 스코프가 필수 — 소속 조직 미배정 계정은\n*  스코프를 정의할 수 없어 로그인 불가. 원인 파악이 가능하도록 자격 오류와 구분해 내려준다.","hangul_chars":65,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":163,"line_end":163,"block_type":"line","text":"* 목업 기준: 조직관리자는 자기 소속 노드 부분트리 운영 전반 가능(정산·결제 제외).","hangul_chars":32,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/auth.service.ts","lang":"js","line_start":166,"line_end":166,"block_type":"line","text":"* 조직관리자(CORP_ORG)는 orgPath 하위로 스코프된다. 쓰기 API는 @AllowOrgWrite + 서비스 스코프 검증으로 제한.","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/car-view-admin.guard.spec.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 기획(2026-07): 기업/조직관리자 자동차분석 허용 — 토큰 발급 시 자기 기업 스코프 검증이 전제","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/car-view-admin.guard.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"* admin-view v2 토큰 경유 요청은 발급 시 서명된 carView claim을 그대로 따른다.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/car-view-admin.guard.ts","lang":"js","line_start":23,"line_end":26,"block_type":"line","text":"* 기획(2026-07): 기업/조직관리자도 자동차분석 열람 허용.\n*  corp의 admin-view 토큰은 발급 시 자기 기업 스코프(isOddInCorpScope)가 검증되므로 타 기업\n*  분석 건은 토큰 자체가 발급되지 않는다. (admin-view 경로의 req.admin은 토큰으로만 복원되어\n*  쿠키 신원만으로는 이 가드를 통과할 수 없고, 쿠키 경로(원본다운로드)는 guardCorp가 스코프 검증)","hangul_chars":106,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/car-view-admin.guard.ts","lang":"js","line_start":40,"line_end":40,"block_type":"jsdoc","text":"자동차 분석 원문: allowlist 최고관리자 + 자기 기업 스코프의 기업/조직관리자만 조회. 빈 allowlist는 admin에 대해 fail-closed.","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-analysis-view.guard.ts","lang":"js","line_start":15,"line_end":15,"block_type":"line","text":"* 핸들러/컨트롤러에 필요한 분석관리 노출레벨을 지정 (1: 분석목록 | 2: 상세팝업 포함)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-analysis-view.guard.ts","lang":"js","line_start":19,"line_end":21,"block_type":"line","text":"* 기업관리자/조직관리자(role='corp')의 분석관리 접근을 tn_agency.agc_analysis_view 로 게이팅.\n*   0: 미노출 | 1: 분석목록만 | 2: 분석목록+상세팝업. admin/sales는 무영향.\n*   설정 변경 즉시 반영을 위해 토큰이 아닌 DB를 조회한다.","hangul_chars":63,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-analysis-view.guard.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 기업 측 관리자가 아니면 통과","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-readonly.guard.ts","lang":"js","line_start":10,"line_end":11,"block_type":"line","text":"* 조직관리자(corpScope='ORG') 쓰기 API 기본 차단.\n*   ORG + 비-GET + @AllowOrgWrite 없음 → 403. 최고관리자(SUPER)/admin/sales는 무영향.","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-readonly.guard.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"* 조직관리자가 아니면 통과 (SUPER corp / admin / sales / 미인증은 여기서 안 막음)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-readonly.guard.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"* 조회(GET)는 항상 허용","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/corp-readonly.guard.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"* 명시적 쓰기 허용 예외","hangul_chars":9,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/jwt.guard.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"스웨거 편리성을 위하여 개발서버인 경우 강제주입","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/roles.guard.ts","lang":"js","line_start":15,"line_end":15,"block_type":"line","text":"1. 필요한 role 메타데이터 추출","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/roles.guard.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"메타데이터가 선언되지 않아서 아예 없을 경우 통과","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/roles.guard.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"2. 사용자 정보에서 role 추출(accessToken 생성시 payload에 포함)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/admin/roles.guard.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"3. 권한 일치 시 통과","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":8,"line_end":11,"block_type":"jsdoc","text":"[드림시큐리티] 본인인증 서비스 구현체\ndocs: https://manager.mobile-ok.com/guide/mok_api_guide/","hangul_chars":16,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"block","text":"본인확인 서비스 용도","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":31,"line_end":31,"block_type":"block","text":"01001 : 회원가입, 01002 : 정보변경, 01003 : ID찾기, 01004 : 비밀번호찾기, 01005 : 본인확인용, 01006 : 성인인증, 01007 : 상품구매/결제, 01999 : 기타","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"block","text":"본인확인 서비스 ID","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"block","text":"암호화된 본인확인 거래 요청 정보","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":37,"line_end":37,"block_type":"block","text":"이용상품 코드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"block","text":"이용상품 코드, telcoAuth : 휴대폰본인확인 (SMS인증시 인증번호 발송 방식 \"SMS\")","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":39,"line_end":39,"block_type":"block","text":"이용상품 코드, telcoAuth-LMS : 휴대폰본인확인 (SMS인증시 인증번호 발송 방식 \"LMS\")","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":41,"line_end":41,"block_type":"block","text":"본인확인 결과 타입","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"block","text":"본인확인 결과 타입, \"MOKToken\"  : 개인정보 응답결과를 이용기관 서버에서 본인확인 서버에 요청하여 수신 후 처리","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/mok-auth.service.ts","lang":"js","line_start":44,"line_end":44,"block_type":"block","text":"본인확인 결과 수신 URL","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth-guard.service.ts","lang":"js","line_start":10,"line_end":11,"block_type":"line","text":"* 로그인아이디는 (mem_login_id, agc_id) 복합 유니크라 기업 간 중복될 수 있음.\n* 매 요청 재검증은 토큰의 유니크 PK(memId)로 조회해 로그인한 회원과 동일 회원을 검증한다.","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 옛 _aT 잔재 제거 후 새 토큰 set (옵션 통일 — 누적/만료토큰 우선읽힘 방지)","hangul_chars":25,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"브릿지로 전달하기 위해 추가","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"* 앱환경 구분을 위해 네이티브 세팅한 userAgent값 검증","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 앱환경에서 로그아웃시 DB에 저장되어있는 refreshToken 공백처리","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":131,"line_end":131,"block_type":"line","text":"* set 과 동일 옵션으로 삭제해야 실제로 지워진다(옵션 불일치 시 옛 쿠키 잔존)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"* 옛 _aT 잔재 제거 후 새 토큰 set (옵션 통일)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.controller.ts","lang":"js","line_start":168,"line_end":168,"block_type":"line","text":"브릿지로 전달하기 위해 추가","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.dto.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"TODO: tnSalesAgency entity.ts 추가 시 SalesAgency 경로 수정 필요","hangul_chars":9,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":62,"line_end":66,"block_type":"jsdoc","text":"* 추천인 코드 생성 (6자리, 헷갈리는 문자 제외)\n* - 대문자 영문 (O, I, L 제외) + 숫자 (0, 1 제외)\n* - 총 31가지 문자 조합 (A-Z 중 23개 + 2-9 중 8개)","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"헷갈리는 문자 제외: O(영문), I(영문), L(영문), 0(숫자), 1(숫자)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":81,"line_end":83,"block_type":"jsdoc","text":"* 추천인 혜택 지급 처리","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"1. 추천인 혜택 설정 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"2. 추천인 조회 (referralCode로 memMyReferralCode 매칭)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":105,"line_end":105,"block_type":"line","text":"3. 유효기간 설정","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":109,"line_end":109,"block_type":"line","text":"4. 추천인에게 혜택 지급","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"5. 피추천인(가입자)에게 혜택 지급","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":133,"line_end":134,"block_type":"line","text":"추천인 카운트는 별도 스키마 변경이 필요하여 생략\n(tn_member에 referral_count 컬럼이 없음)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"가입 자체는 성공해야 하므로 에러를 throw하지 않음","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":178,"line_end":178,"block_type":"line","text":"* 나의 추천인 코드 생성 (일반회원만, 중복 체크)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":181,"line_end":181,"block_type":"line","text":"일반회원인 경우에만 추천인 코드 생성","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"agcId: 1, // 일반회원 고정","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":221,"line_end":221,"block_type":"line","text":"* 탈퇴이력여부체크","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":231,"line_end":231,"block_type":"line","text":"* 체험상품구독하기","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":237,"line_end":237,"block_type":"line","text":"* 추천인 코드가 있으면 추천인에게 혜택 지급","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":293,"line_end":293,"block_type":"line","text":"* 회원타입이 기업인데 불량회원일 경우","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":314,"line_end":314,"block_type":"line","text":"* 앱 환경일 경우에만 실행","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":316,"line_end":316,"block_type":"line","text":"* 앱 자동로그인을 위한 refresh_token 추가 작업(25.03.25)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"* 앱 자동 로그인을 위한 refresh token member에 저장","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":464,"line_end":464,"block_type":"line","text":"* 앱에서 전달되는 FCM 토큰 member 테이블에 업데이트","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":466,"line_end":466,"block_type":"line","text":"* 기존 유저 토큰 정보 확인","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":485,"line_end":485,"block_type":"line","text":"* 현재 갱신하려는 토큰 정보를 이미 가지고 있는 다른 멤버가 있을 경우 해당 멤버 토큰 제거","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":497,"line_end":497,"block_type":"line","text":"ids가 1개 이상 있을 경우 업데이트로 fcmToken clear","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":507,"line_end":508,"block_type":"line","text":"* 현재 DB에 저장되어있는 토큰과 토큰값이 다를 경우 갱신\n* FCM 토큰의 경우 앱이 삭제되거나 하였을시 값이 변경된다고 함","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":521,"line_end":521,"block_type":"line","text":"* refresh 토큰을 통한 앱 자동로그인 기능","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":525,"line_end":525,"block_type":"line","text":"* 앱에서 JSON 형태로 토큰이 전달되는 경우 실제 refreshToken 추출","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":533,"line_end":533,"block_type":"line","text":"* 토큰에서 memId 추출","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":545,"line_end":545,"block_type":"line","text":"* 토큰 유효기간이 만료되었을 경우 예외처리","hangul_chars":18,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":550,"line_end":550,"block_type":"line","text":"* 토큰에서 memId 값을 찾을 수 없을 경우 예외처리","hangul_chars":17,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":555,"line_end":555,"block_type":"line","text":"* DB 리프레쉬 토큰 존재여부 확인","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":583,"line_end":583,"block_type":"line","text":"* 회원정보가 없을 경우","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":588,"line_end":588,"block_type":"line","text":"* 회원타입이 기업인데 불량회원일 경우","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":595,"line_end":595,"block_type":"line","text":"* refresh 토큰으로 가져온 멤버 id와 refresh 토큰에 저장된 id가 다를 경우","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/auth.service.ts","lang":"js","line_start":648,"line_end":648,"block_type":"line","text":"* 로그아웃시 유저 테이블의 refreshToken 제거","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":14,"line_end":17,"block_type":"jsdoc","text":"Optional JWT Guard\nJWT 토큰이 있으면 검증하고, 없으면 통과시킴 (B2C 지원용)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* _aT 후보(옛 만료 + 새 유효 중복 가능) + 헤더 토큰 중 verify 성공하는 것을 쓴다.","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"화이트리스트 IP","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"토큰이 없으면 그냥 통과 (B2C의 경우)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 유효한 토큰을 찾으면 사용","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"다음 후보 시도","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"JWT 검증 실패해도 통과 (B2C 지원)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"유저 차단 혹은 중단 여부 체크 로직","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt-optional.guard.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"기업 회원이 연체 상태일 때만 차단","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt.guard.ts","lang":"js","line_start":36,"line_end":37,"block_type":"line","text":"* _aT가 여러 개(옛 만료 + 새 유효)거나 헤더 토큰이 있을 수 있어, 후보 중 verify 성공하는 토큰을 쓴다.\n* (cookie-parser는 첫 번째 _aT만 담아, 옛 만료 토큰이 먼저 읽혀 로그인 직후 튕기던 문제 해결)","hangul_chars":63,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt.guard.ts","lang":"js","line_start":40,"line_end":42,"block_type":"line","text":"* ★보안(H1): x-forwarded-for는 클라가 위조 가능(ALB는 덮어쓰지 않고 append) → 이 IP 화이트리스트로\n*   JWT 검증 실패를 DEV_USER로 통과시키던 건 스푸핑 백도어다. 운영(production)에선 비활성 —\n*   개발/스테이징 편의로만 유지하고 운영은 정상 토큰을 강제한다.","hangul_chars":77,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt.guard.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 유효한 토큰을 찾으면 사용","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt.guard.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"화이트리스트 IP는 JWT 검증 실패해도 DEV_USER로 통과","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/jwt.guard.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"유저 차단 혹은 중단 여부 체크 로직","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/own-analysis.guard.ts","lang":"js","line_start":10,"line_end":19,"block_type":"jsdoc","text":"회원용 분석 조회(oddId 기반)에서 \"요청자 == 분석 소유자\"를 강제한다.\n\n배경: 이 컨트롤러의 조회들은 소유자 검증이 없어 oddId만 바꾸면 남의 고객\n분석(이름/생년/연락처/진료·처방 이력)이 그대로 조회됐다. 자부상(car-basic)만\n서비스 단에서 소유자를 대조하고 있었고 나머지는 무방비였다.\n\n토큰이 없거나 memId가 없으면 -1로 떨어져 어떤 주문과도 일치하지 않으므로\nfail-closed로 차단된다.","hangul_chars":138,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/own-analysis.guard.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* oddId 파라미터가 없는 라우트(asbId/acbId 등)는 각 서비스의 기존 검증에 맡긴다.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/auth/user/own-analysis.guard.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 형식 오류는 ParseIntPipe가 처리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 권한 신규 등록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"* 권한 수정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"권한정보 수정","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"현재 등록된 메뉴 전부 삭제","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"설정한 메뉴 등록","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"메뉴정보 불러오기","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"메뉴정보 맵핑 등록","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"* 권한 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"* 권한과 엮인 메뉴 id 배열","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"* 목록 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.repository.ts","lang":"js","line_start":140,"line_end":140,"block_type":"line","text":"* 권한 메뉴 목록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.service.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"* 권한 목록 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 권한 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.service.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 권한 신규 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.service.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"* 권한 수정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/authority/authority.service.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"* 권한 삭제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin-view.controller.ts","lang":"js","line_start":31,"line_end":36,"block_type":"jsdoc","text":"관리자 전용 B2C 분석 API\n- 관리자가 iframe으로 B2C 분석 상세를 조회할 때 사용 (/admin-view/b2c-analyze/:bodId/*)\n- ★보안(C2): AdminViewTokenGuard로 scope(b2c-analyze)+bodId 스코프 단명 토큰(?t=) 검증.\n  ADMIN_VIEW_TOKEN_ENFORCE='true' 시 차단 활성(그 전엔 경고 로그만=무중단).","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin-view.controller.ts","lang":"js","line_start":166,"line_end":166,"block_type":"line","text":"B2C 주문 및 사용자 정보 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin-view.controller.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"자동차보험 데이터 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin-view.controller.ts","lang":"js","line_start":183,"line_end":183,"block_type":"line","text":"count 계산 (전체 데이터 조회)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"B2C 분석 상태 enum","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":25,"line_end":25,"block_type":"line","text":"인증요청중","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"자료수집실패","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"자료분석중","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"분석완료","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.dto.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"분석실패","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"B2C 분석 목록조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":36,"line_end":36,"block_type":"jsdoc","text":"B2C 분석 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":58,"line_end":58,"block_type":"jsdoc","text":"원본데이터 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":123,"line_end":123,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":206,"line_end":206,"block_type":"jsdoc","text":"B2C 분석 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"jsdoc","text":"기업 회원 목록 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":217,"line_end":217,"block_type":"line","text":"기업 소속 회원 목록 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":228,"line_end":228,"block_type":"jsdoc","text":"B2C 분석 수정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":239,"line_end":239,"block_type":"jsdoc","text":"담당자 지정","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":241,"line_end":241,"block_type":"line","text":"B2C 주문 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":247,"line_end":247,"block_type":"line","text":"회원 정보 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/b2c/analyze/b2c-analyze-admin.service.ts","lang":"js","line_start":253,"line_end":253,"block_type":"line","text":"담당자 지정 (담당지정여부: 1(지정), 담당회원아이디, 담당지정일 업데이트)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/banner/banner.service.ts","lang":"js","line_start":92,"line_end":92,"block_type":"jsdoc","text":"상품 신규등록 이미지 데이터","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/banner/banner.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"jsdoc","text":"s3 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board-admin.controller.ts","lang":"js","line_start":143,"line_end":143,"block_type":"line","text":"* editor 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.controller.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* 하단의 동적 id 매핑이 content보다 먼저 있을 경우 content도 id로 인식되어 상단에 배치","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"* 조사선정 기준 기능의 경우 노출로 등록시 기존 노출상태였던 게시글 미노출로 변경 필요","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"* 파일이 있을 경우","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":150,"line_end":150,"block_type":"line","text":"* 카테고리가 있을 경우","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":171,"line_end":171,"block_type":"line","text":"* 조사선정 기준인 게시글이 노출로 변경될 경우 다른 게시글 미노출로 처리","hangul_chars":30,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":181,"line_end":181,"block_type":"line","text":"* 게시글 수정","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":193,"line_end":193,"block_type":"line","text":"* 파일 관련","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":196,"line_end":196,"block_type":"line","text":"* 삭제할 파일 id가 있을 경우 삭제","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":203,"line_end":203,"block_type":"line","text":"* 파일이 있을 경우","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.repository.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"* 카테고리가 있을 경우","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 게시글 신규등록","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 게시글 수정","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":96,"line_end":96,"block_type":"jsdoc","text":"s3 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"이미 존재하는 파일들","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":171,"line_end":171,"block_type":"line","text":"요청된 파일명들","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":173,"line_end":173,"block_type":"line","text":"삭제되는 파일 id들","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":180,"line_end":180,"block_type":"line","text":"새로 추가되는 파일들","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":186,"line_end":186,"block_type":"jsdoc","text":"삭제되는 파일 id들 추출","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":202,"line_end":202,"block_type":"jsdoc","text":"새로 추가되는 파일들 추출","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/board/board/board.service.ts","lang":"js","line_start":217,"line_end":217,"block_type":"line","text":"새로 추가되는 파일들 업로드","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/card/card.repository.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* 신규카드 대표카드 등록","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/card/card.service.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"카드 번호 맨 뒤 4자리만 반환","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/card/card.service.ts","lang":"js","line_start":40,"line_end":41,"block_type":"line","text":"----------------------------------------- toss billing key -----------------------------------------//\n* customerKey는 memId를 암호화한 값","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/card/card.service.ts","lang":"js","line_start":50,"line_end":57,"block_type":"line","text":"! 카드중복검사 우선 주석처리\n동일한 customerKey/동일한 카드여도 다른 빌링키값으로 들어오기 때문에 카드 중복검사가 잘 안될 수도 있음\nconst duplicateWhere = await this.cardRepository.whereClause({\n  searchId: memId,\n  crdNumber: issue.card.number,\n});\nconst duplicate = await this.cardRepository.count(duplicateWhere);\nif (duplicate !== 0) throw new BadRequestException(DUPLICATE_CARD);","hangul_chars":51,"class":"2_rationale","tags":["2_rationale","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/card/card.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"TODO 양방향 암호화 필요여부 체크","hangul_chars":12,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin-view.controller.ts","lang":"js","line_start":29,"line_end":34,"block_type":"jsdoc","text":"관리자 전용 고객사 분석 API\n- 관리자가 iframe으로 분석 상세를 조회할 때 사용 (/admin-view/client-analyze/:codId/*)\n- ★보안(C2): AdminViewTokenGuard로 scope(client-analyze)+codId 스코프 단명 토큰(?t=) 검증.\n  ADMIN_VIEW_TOKEN_ENFORCE='true' 시 차단 활성(그 전엔 경고 로그만=무중단).","hangul_chars":55,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.dto.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.dto.ts","lang":"js","line_start":161,"line_end":161,"block_type":"line","text":"* 자동차 보험","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.dto.ts","lang":"js","line_start":423,"line_end":423,"block_type":"line","text":"* 자동차 보험 Response","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.dto.ts","lang":"js","line_start":474,"line_end":474,"block_type":"line","text":"* PDF처리를 위한 분석데이터(숨은보험금) 탭별 전체 처리","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"*분석결과기본","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"*분석결과상세","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"* 분석기본정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":70,"line_end":71,"block_type":"line","text":"* 5년내 7일이상 진료/30일이상 투약 기본\n* 11(6)대 질병진단/수술 기본","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":89,"line_end":89,"block_type":"line","text":"* 처방조제정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"* 원본데이터 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"TODO ExcelService로 추후 빼기","hangul_chars":5,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":175,"line_end":175,"block_type":"line","text":"* 분석결과기본(자동차보험)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"* 분석결과상세(자동차보험)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 분석결과 숨은 보험금 전체 목록(PDF 다운로드용)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"* 숨은보험금 진단 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":229,"line_end":229,"block_type":"line","text":"* 숨은보험금 수술 정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"* 숨은보험금 치아","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":259,"line_end":259,"block_type":"line","text":"* 숨은보험금 기타","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":331,"line_end":331,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":372,"line_end":372,"block_type":"line","text":"* 자동차 보험 추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":387,"line_end":387,"block_type":"line","text":"* 자동차 보험(상세) 추가","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":452,"line_end":452,"block_type":"line","text":"CCT007A: 건강체 5년 내 7일이상 진료 (중분류 그루핑)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":461,"line_end":461,"block_type":"line","text":"CCT007B: 건강체 5년 내 30일이상 투약 (약효 카테고리 그루핑)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":470,"line_end":470,"block_type":"line","text":"동일 진단코드 내원 그룹 조회 (5년 내, 2건 이상, 약국 포함)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":479,"line_end":479,"block_type":"line","text":"치아 숨은보험금 그룹 조회 (ANS007)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-admin.service.ts","lang":"js","line_start":488,"line_end":488,"block_type":"line","text":"기타 숨은보험금 그룹 조회 (ANS009)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-detail.entity.ts","lang":"js","line_start":44,"line_end":47,"block_type":"line","text":"@ApiProperty({ description: '분석대조한 투약' })\n@IsString()\n@IsOptional()\ncasdDrug?: string;","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-detail.entity.ts","lang":"js","line_start":49,"line_end":52,"block_type":"line","text":"@ApiProperty({ description: '투약알릴사항' })\n@IsString()\n@IsOptional()\ncasdDrugNotice?: string;","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-detail.entity.ts","lang":"js","line_start":54,"line_end":56,"block_type":"line","text":"@ApiProperty({ description: '방문일수' })\n@IsInt()\ncasdVisitDays;","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-detail.entity.ts","lang":"js","line_start":58,"line_end":60,"block_type":"line","text":"@ApiProperty({ description: '조제정보 MAX ID' })\n@IsInt()\ncasdDosingId;","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":78,"line_end":79,"block_type":"line","text":"------------------------- private -------------------------//\n\"약국\"이 포함된 병원명을 제외하는 조건 추가","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":87,"line_end":89,"block_type":"line","text":"if (!dto || !date) {\n  throw new Error('필수 파라미터 누락 (dto, date)');\n}","hangul_chars":8,"class":"1_policy","tags":["1_policy","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"3개월이내(내원, 수술, 검사, 투약, 기타)/유병자는 투약만 제외","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":106,"line_end":106,"block_type":"line","text":"1년이내 검사","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"5년이내 7일이상 치료 / 30일이상 투약일시엔 해당 basic이 상세가 됨","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":131,"line_end":131,"block_type":"line","text":"5년이내 입원/수술 (유병자의 경우 2년이내, 5년이내)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":134,"line_end":134,"block_type":"line","text":"ANS004 공통 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":152,"line_end":153,"block_type":"line","text":"5년이내 11(6)대 질병 진단, 수술\nANS003과 조건이 동일하지만 조건이 변경될 수 있으니 따로 구성함","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"숨은보험(진단), 약국포함, 기본진단","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"숨은보험(치아) 기본진단 and 상세치료","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":185,"line_end":185,"block_type":"line","text":"숨은보험(수술) 상세치료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":191,"line_end":191,"block_type":"line","text":"숨은보험(기타) 상세치료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"치아고지(틀니) 기본진단 or 상세치료","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":206,"line_end":206,"block_type":"line","text":"치아고지(1년) 기본진단 and 상세치료","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"치아고지(5년) 기본진단 and 상세치료","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":227,"line_end":227,"block_type":"line","text":"주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":254,"line_end":255,"block_type":"line","text":"수술, 검사, 투약만\n투약은 다른 수술/검사가 있을 경우 투약항목에 포함 됨","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":264,"line_end":264,"block_type":"line","text":"1년이내 검사","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":269,"line_end":269,"block_type":"line","text":"5년이내 입원/수술","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"숨은보험(치아)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"숨은보험(수술)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":285,"line_end":285,"block_type":"line","text":"숨은보험(기타)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":290,"line_end":290,"block_type":"line","text":"치아고지(틀니)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":295,"line_end":295,"block_type":"line","text":"치아고지(1년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":300,"line_end":300,"block_type":"line","text":"치아고지(5년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":309,"line_end":310,"block_type":"line","text":"------------------------- ansType별 공통 조건 -------------------------//\nANS002: 1년이내 검사","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":316,"line_end":316,"block_type":"line","text":"ANS007: 숨은보험(치아)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":322,"line_end":322,"block_type":"line","text":"ANS008: 숨은보험(수술)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":328,"line_end":328,"block_type":"line","text":"ANS009: 숨은보험(기타)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":334,"line_end":334,"block_type":"line","text":"ANS010: 치아고지(틀니)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":340,"line_end":340,"block_type":"line","text":"ANS011: 치아고지 (1년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze-where.builder.ts","lang":"js","line_start":346,"line_end":346,"block_type":"line","text":"ANS012: 치아고지 (5년)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* 약국의 경우 투약일수를 정확하게 매칭이 가능하므로, 약국일 경우엔 casdDosingDays로 병원은 casbDosingDays","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"* 분석상세의 각 항목에 대한 1건 도출","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 분석상세의 각 항목에 대한 상세 수량","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":169,"line_end":169,"block_type":"line","text":"* count가 groupBy로 묶이므로 groupBy가 있는 곳은 length로 가져올 것","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":231,"line_end":238,"block_type":"jsdoc","text":"(ANS003) 5년내 7일이상 진료, 30일이상 투약\n(ANS005) 5년내 질병, 진단\n(ANS006) 숨은보험 진단\n@param id\n@param dto\n@returns","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"* 숨은보험진단(ANS006), 보상찾아줘-기타(ANS009)의 경우만 약국도 포함","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":253,"line_end":253,"block_type":"line","text":"* ANS009(보상찾아줘-기타)일 경우 casdInEtc별로 행을 분리해야 하므로 GROUP BY에 포함","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":271,"line_end":271,"block_type":"line","text":"투약중복여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":272,"line_end":272,"block_type":"line","text":"상세의 요약 1건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":291,"line_end":294,"block_type":"jsdoc","text":"2차쿼리 조건절\nANS003일 경우 외래만 가져오는 것으로 조건 추가됨","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":331,"line_end":338,"block_type":"jsdoc","text":"최종 쿼리의 조건절\nANS003일 경우 7일이상 치료 또는 30일이상 투약의 건\nANS006(숨은보험진단)의 건강체일 경우, 질병에 해당하는 건\nANS009(보상찾아줘-기타)일 경우 숨은보험기타 해당하는 건\nANS013(주의사항)일 경우 주의사항 해당하는 건\nANS005의 유병자일 경우, 유병자질병에 해당하는 건","hangul_chars":101,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":460,"line_end":460,"block_type":"line","text":"* 자동차 보험 추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":569,"line_end":570,"block_type":"line","text":"------------------------- schedule -------------------------//\n* 스케줄러를 통한 30일 경과시 분석결과 데이터 삭제(기본, 상세, 자동차진료기본, 자동차진료상세)","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":575,"line_end":575,"block_type":"line","text":"* 생성된지 30일이 지난 주문상세건 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":583,"line_end":583,"block_type":"line","text":"* id값만 추출해 number 배열 생성","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":586,"line_end":587,"block_type":"line","text":"* 주문 id 기준으로 분석결과 정보 삭제\n* 삭제된 주문 상세건의 연결된 user_id 정보도 null 처리","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":623,"line_end":624,"block_type":"line","text":"------------------------- api용 -------------------------//\n고객사 분석결과 조회 (숨은보험-진단)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":626,"line_end":626,"block_type":"line","text":"* 숨은보험진단(ANS006)의 경우만 약국도 포함","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":629,"line_end":629,"block_type":"line","text":"기본분석데이터에서 해당 주문건 정보 다 가져옴","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":632,"line_end":632,"block_type":"line","text":"해당 주문건의 기본분석데이터들을 진단명, 진단코드로 그룹화하여 최소, 최대, 합계, 개수 구함","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":635,"line_end":638,"block_type":"jsdoc","text":"최종 쿼리의 조건절\n숨은진단이 존재해야함","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":641,"line_end":641,"block_type":"line","text":"최종 계산데이터","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":680,"line_end":680,"block_type":"line","text":"고객사 분석결과 조회 (숨은보험-수술)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":719,"line_end":719,"block_type":"line","text":"고객사 분석결과 조회 (숨은보험-치아)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":759,"line_end":759,"block_type":"line","text":"고객사 분석결과 조회 (숨은보험-기타) - 숨은보험내용별 그루핑","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":770,"line_end":770,"block_type":"line","text":"진단코드별 flat list (Notice 패턴과 동일 - basic 테이블만 JOIN)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":813,"line_end":813,"block_type":"line","text":"숨은보험내용(inEtc) 텍스트 기준으로 그룹핑 (getClientAnalyzeNotice 패턴)","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":884,"line_end":884,"block_type":"line","text":"------------------------- 건강체 분석결과 api용 -------------------------//","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":886,"line_end":886,"block_type":"line","text":"CCT005: 건강체 3개월 내 (ANS001 패턴)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":946,"line_end":946,"block_type":"line","text":"CCT006: 건강체 1년 내 검사 (ANS002 패턴)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":996,"line_end":996,"block_type":"line","text":"CCT007: 건강체 5년 내 7일/30일 투약 (ANS003 패턴 - aggregate)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1052,"line_end":1052,"block_type":"line","text":"CCT008: 건강체 5년 내 입원/수술 (ANS004 패턴)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1102,"line_end":1102,"block_type":"line","text":"CCT009: 건강체 5년 내 11대 중대질병 (ANS005 패턴 - aggregate)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1160,"line_end":1160,"block_type":"line","text":"------------------------- 유병자 분석결과 api용 -------------------------//","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1162,"line_end":1162,"block_type":"line","text":"CCT010: 유병자 3개월 내 (ANS001 패턴)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1222,"line_end":1222,"block_type":"line","text":"CCT011: 유병자 2년 내 입원/수술 (ANS004 패턴)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1273,"line_end":1273,"block_type":"line","text":"CCT012: 유병자 5년 내 입원/수술 (ANS004 패턴)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1321,"line_end":1321,"block_type":"line","text":"CCT013: 유병자 5년 내 6대 중대질병 (ANS005 패턴 - aggregate)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1377,"line_end":1378,"block_type":"line","text":"CCT014: 주의사항 (ANS013 패턴 - aggregate)\n주의사항 텍스트 기준으로 그룹핑 → 진단코드별 목록 → 병원 상세","hangul_chars":31,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1391,"line_end":1391,"block_type":"line","text":"진단코드별 flat list (기존 쿼리)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1429,"line_end":1429,"block_type":"line","text":"주의사항 텍스트 기준으로 그룹핑","hangul_chars":14,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1453,"line_end":1454,"block_type":"line","text":"------------------------- 공통 -------------------------//\n기본분석데이터에서 해당 주문건 정보 다 가져옴","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1473,"line_end":1473,"block_type":"line","text":"투약중복여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1474,"line_end":1474,"block_type":"line","text":"상세의 요약 1건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1475,"line_end":1475,"block_type":"line","text":"숨은보험기타","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1491,"line_end":1491,"block_type":"line","text":"해당 주문건의 기본분석데이터들을 진단명, 진단코드로 그룹화하여 최소, 최대, 합계, 개수 구함","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1524,"line_end":1524,"block_type":"line","text":"------------------------- 질병코드 → 중분류 배치 매핑 -------------------------//","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1529,"line_end":1530,"block_type":"line","text":"3순위: sub_fine → fine → detail 순으로 덮어씌워 detail이 최종 우선\n모든 비교에 COLLATE 명시 (테이블 간 collation 불일치 방지, 원본 COALESCE와 동일)","hangul_chars":35,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1587,"line_end":1587,"block_type":"line","text":"------------------------- CCT023: 건강체 5년 내 7일이상 진료 (중분류 그루핑) -------------------------//","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1589,"line_end":1590,"block_type":"line","text":"[TEMP-PROD-REVERT 2026-04-05] tt_client_treat_basic 직접 조회 (검증 완료 전까지)\n성능 최적화: 행별 COALESCE 서브쿼리 6개 → 2단계 배치 매핑으로 변환","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1605,"line_end":1605,"block_type":"line","text":"Step 1: tt_client_treat_basic 단순 조회 (서브쿼리 없음)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1627,"line_end":1627,"block_type":"line","text":"Step 2: 유니크 질병코드 배치 매핑 (detail → fine → sub_fine 우선순위)","hangul_chars":15,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1631,"line_end":1631,"block_type":"line","text":"Step 3: 메모리에서 조합 (중분류 매핑 실패한 레코드 제외 - 프로시저 동작과 동일)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1641,"line_end":1641,"block_type":"line","text":"1차 그루핑: 중분류(middleCode) - 외래 기준 totalVisitDays 계산","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1680,"line_end":1680,"block_type":"line","text":"외래 기준 7일 이상 필터 + 2차 그루핑: 세분류(diseaseCode)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1684,"line_end":1684,"block_type":"line","text":"2차 그루핑: 소분류 (diseaseCode 앞 3자리)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1727,"line_end":1727,"block_type":"line","text":"------------------------- CCT024: 건강체 5년 내 30일이상 투약 (약효 카테고리 그루핑) -------------------------//","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1729,"line_end":1733,"block_type":"line","text":"[TEMP-PROD-REVERT 2026-04-05] 운영 임시 원복: 신규 분석 테이블(tn_client_analysis_dosing_record) 검증 완료 전까지\ntt_client_treat_prescribe 직접 조회로 되돌림. PROC_COMPARE_CLIENT_DOSING_RECORD 의 적재 로직을 read-time으로 재수행:\n  - 고객사 주문 생성일 기준 5년 이내 + hospital NOT LIKE '%약국%'\n  - tc_medication_standard 매칭(공백 제거 후 drug_name = msc_code), tc_medication_category 조인\n  - 이후 in-memory 카테고리 집계 + 30일 이상 필터는 기존 로직 그대로 유지","hangul_chars":86,"class":"1_policy","tags":["1_policy","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.repository.ts","lang":"js","line_start":1771,"line_end":1771,"block_type":"line","text":"카테고리별 그루핑 + 집계 + 30일 필터","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"*------------------------ 숨은보험 분석결과 ------------------------*//","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"*------------------------ 자동차 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"*------------------------ 건강체 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"CCT005: 건강체 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"CCT006: 건강체 1년 내 검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"CCT007: 건강체 5년 내 7일/30일 투약","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"CCT023: 건강체 5년 내 7일이상 진료 (중분류 그루핑)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"CCT024: 건강체 5년 내 30일이상 투약 (약효 카테고리 그루핑)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"CCT008: 건강체 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"CCT009: 건강체 5년 내 11대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":83,"line_end":83,"block_type":"line","text":"*------------------------ 유병자 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"CCT010: 유병자 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"CCT011: 유병자 2년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"CCT012: 유병자 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"CCT013: 유병자 5년 내 6대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"*------------------------ 주의사항 분석결과 ------------------------*//","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"CCT014: 주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"*------------------------ viewName 후처리 (코드명=코드노출명 → NULL) ------------------------*//","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":140,"line_end":142,"block_type":"jsdoc","text":"값이 viewName 없는 코드명인지 체크","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":161,"line_end":164,"block_type":"jsdoc","text":"detailList JSON 배열 내의 compare 필드를 codeName과 비교하여 NULL 변환\ncodeName과 공백제거 후 동일하면 viewName이 없는 것","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":192,"line_end":194,"block_type":"jsdoc","text":"top-level의 compare detail 필드를 hiddenNames Set으로 NULL 변환","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/analyze/client-analyze.service.ts","lang":"js","line_start":211,"line_end":213,"block_type":"jsdoc","text":"top-level의 compare basic 필드를 hiddenNames Set으로 NULL 변환","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"건강체/유병자 분석 DTO","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"병력분석 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"*------------------------ 숨은보험 분석결과 ------------------------*//","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":187,"line_end":187,"block_type":"line","text":"*------------------------ 자동차 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":209,"line_end":209,"block_type":"line","text":"*------------------------ 건강체 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":372,"line_end":372,"block_type":"line","text":"*------------------------ 유병자 분석결과 ------------------------*//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":466,"line_end":466,"block_type":"line","text":"*------------------------ 주의사항 분석결과 ------------------------*//","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.controller.ts","lang":"js","line_start":491,"line_end":491,"block_type":"line","text":"*------------------------ 병력분석 결과 ------------------------*//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":14,"line_end":14,"block_type":"jsdoc","text":"숨은보험 - 진단","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":16,"line_end":16,"block_type":"jsdoc","text":"숨은보험 - 수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"숨은보험 - 치아","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"숨은보험 - 기타","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":22,"line_end":22,"block_type":"jsdoc","text":"건강체 - 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":24,"line_end":24,"block_type":"jsdoc","text":"건강체 - 1년 내 검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":26,"line_end":26,"block_type":"jsdoc","text":"건강체 - 5년 내 7일/30일 투약","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":28,"line_end":28,"block_type":"jsdoc","text":"건강체 - 5년 내 7일이상 진료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":30,"line_end":30,"block_type":"jsdoc","text":"건강체 - 5년 내 30일이상 투약","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":32,"line_end":32,"block_type":"jsdoc","text":"건강체 - 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":34,"line_end":34,"block_type":"jsdoc","text":"건강체 - 5년 내 11대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":36,"line_end":36,"block_type":"jsdoc","text":"유병자 - 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":38,"line_end":38,"block_type":"jsdoc","text":"유병자 - 2년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":40,"line_end":40,"block_type":"jsdoc","text":"유병자 - 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":42,"line_end":42,"block_type":"jsdoc","text":"유병자 - 5년 내 6대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":44,"line_end":44,"block_type":"jsdoc","text":"주의사항 - 주의사항","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":46,"line_end":46,"block_type":"jsdoc","text":"치아 - 틀니","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":48,"line_end":48,"block_type":"jsdoc","text":"치아 - 1년 내","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":50,"line_end":50,"block_type":"jsdoc","text":"치아 - 5년 내","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"병력분석 - 진료로그","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":56,"line_end":56,"block_type":"jsdoc","text":"병력분석 - 진단로그","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":58,"line_end":58,"block_type":"jsdoc","text":"병력분석 - 투약로그","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":60,"line_end":60,"block_type":"jsdoc","text":"병력분석 - 검사로그","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":312,"line_end":312,"block_type":"line","text":"---------------- 분석결과조회 ---------------- //","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":636,"line_end":636,"block_type":"line","text":"---------------- 건강체/유병자 분석결과조회 (CCT005~014) ---------------- //","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":679,"line_end":679,"block_type":"line","text":"CCT005, CCT010: 3개월 내 (ANS001 패턴)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":791,"line_end":791,"block_type":"line","text":"CCT006: 1년 내 검사 (ANS002 패턴)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":864,"line_end":864,"block_type":"line","text":"CCT007: 5년 내 7일/30일 투약 (ANS003 패턴)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":940,"line_end":940,"block_type":"line","text":"CCT023: 5년 내 7일이상 진료 (중분류 > 소분류 그루핑)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1030,"line_end":1030,"block_type":"line","text":"CCT024: 5년 내 30일이상 투약 (약효 카테고리 그루핑)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1104,"line_end":1104,"block_type":"line","text":"CCT008, CCT011, CCT012: 입원/수술 (ANS004 패턴)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1197,"line_end":1197,"block_type":"line","text":"CCT009, CCT013: 중대질병 (ANS005 패턴)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1298,"line_end":1298,"block_type":"line","text":"CCT014: 주의사항 (ANS013 패턴)","hangul_chars":6,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1374,"line_end":1374,"block_type":"line","text":"---------------- 병력분석 (CCT019~023) ---------------- //","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1376,"line_end":1376,"block_type":"line","text":"CCT019: 진료로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1436,"line_end":1436,"block_type":"line","text":"CCT020: 진단로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1441,"line_end":1441,"block_type":"line","text":"세세세분류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1463,"line_end":1463,"block_type":"line","text":"세세분류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1593,"line_end":1593,"block_type":"line","text":"CCT022: 투약로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.dto.ts","lang":"js","line_start":1643,"line_end":1643,"block_type":"line","text":"CCT023: 검사로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":49,"line_end":49,"block_type":"line","text":"고객사 전체 목록","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"진단코드 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"고객사 유저정보 생성","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"고객사 원본 진료정보 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":95,"line_end":95,"block_type":"line","text":"* 기본진료정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"Codef 형식(res prefix)과 Client API 형식 모두 지원","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 빈문자('')→NULL 정규화(벤더 통일)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":139,"line_end":139,"block_type":"line","text":"* 세부내역정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":168,"line_end":168,"block_type":"line","text":"* 처방조제정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"* 자동차 진료정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":211,"line_end":211,"block_type":"line","text":"* 기본진료정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":225,"line_end":225,"block_type":"line","text":"*병원/약국명에 해당 글자명이 포함되는지 확인","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":255,"line_end":255,"block_type":"line","text":"* 세부내역정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":302,"line_end":302,"block_type":"line","text":"고객사 진료분석정보 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":304,"line_end":304,"block_type":"jsdoc","text":"자동차 분석 시작","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":305,"line_end":305,"block_type":"line","text":"* 진료정보_자동차(기본) 조회 - 상세는 저장은 해두나 현재 데이터는 미사용","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":312,"line_end":312,"block_type":"line","text":"* 그룹 indedx(같은 그룹일 경우 동일한 index로 처리)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":315,"line_end":315,"block_type":"line","text":"* 분석 기본, 상세 객체 선언","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":346,"line_end":347,"block_type":"line","text":"* 자동차 진료정보(기본)을 통한 진료시작일 기준 3개월 차이가 나는 데이터 그룹화 및 계산\n* 자동차 진료정보(기본)이 없을 시 계산 실행 X","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":351,"line_end":351,"block_type":"line","text":"* 계산된 배열에서 마지막 요소만 가져옴","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":354,"line_end":355,"block_type":"line","text":"* 계산된 배열 마지막 요소가 없을 경우\n* 현재 루프의 item 진료시작일과 계산된 배열 마지막 진료시작일 간의 차이가 3개월 날 경우","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":397,"line_end":397,"block_type":"line","text":"그룹별 합산","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":459,"line_end":459,"block_type":"jsdoc","text":"자동차 분석 종료","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":461,"line_end":461,"block_type":"line","text":"* 트랜잭션 한 블록에 일단 묶어서 처리 해보고 문제가 될 거같을시 분리 필요","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":466,"line_end":466,"block_type":"line","text":"* 자동차 분석 추가(데이터 값이 있을 때만 실행)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":477,"line_end":477,"block_type":"line","text":"날짜 계산을 위해 했던 정렬을 역순으로 재조정","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":501,"line_end":502,"block_type":"line","text":"------------------------------- 고객사(client) ----------------------------//\n* 고객사 목록","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.repository.ts","lang":"js","line_start":600,"line_end":600,"block_type":"line","text":"* 스케줄러를 통한 임시데이터 삭제 (생성일이 30일이 경과된 경우)","hangul_chars":25,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"진단코드 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"진료정보 분석","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* 1-1. CI 횟수제한 체크","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* 3. tn_client_order_detail에 주문정보 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"* 4. 원본데이터 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"* 5. 자료 분석 진행 및 분석데이터 저장","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"분석결과조회 (숨음보험-진단)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":156,"line_end":156,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":186,"line_end":186,"block_type":"line","text":"* 4. 분석결과 조회 (숨음보험-진단)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":195,"line_end":195,"block_type":"line","text":"분석결과조회 (숨은보험-수술)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":202,"line_end":202,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":211,"line_end":211,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":232,"line_end":232,"block_type":"line","text":"* 4. 분석결과 조회 (숨음보험-수술)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":240,"line_end":240,"block_type":"line","text":"분석결과조회 (숨은보험-치아)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":247,"line_end":247,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":256,"line_end":256,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":277,"line_end":277,"block_type":"line","text":"* 4. 분석결과 조회 (숨은보험-치아 그루핑)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":299,"line_end":299,"block_type":"line","text":"분석결과조회 (숨은보험-기타)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":306,"line_end":306,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":315,"line_end":315,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":336,"line_end":336,"block_type":"line","text":"* 4. 분석결과 조회 (숨은보험-치아)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":343,"line_end":343,"block_type":"line","text":"분석결과조회 (숨은보험-기타 그루핑)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":383,"line_end":383,"block_type":"line","text":"Client API 응답 구조로 변환","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":399,"line_end":399,"block_type":"line","text":"분석결과조회 (자동차)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":406,"line_end":406,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":415,"line_end":415,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":438,"line_end":438,"block_type":"line","text":"* 4. 분석결과 조회 (자동차)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":446,"line_end":446,"block_type":"line","text":"*------------------------ 건강체/유병자 분석결과조회 ------------------------*//","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":448,"line_end":448,"block_type":"line","text":"CCT005: 건강체 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":470,"line_end":470,"block_type":"line","text":"CCT006: 건강체 1년 내 검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":493,"line_end":493,"block_type":"line","text":"CCT007: 건강체 5년 내 7일/30일 투약","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":515,"line_end":515,"block_type":"line","text":"CCT023: 건강체 5년 내 7일이상 진료 (중분류 그루핑)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":533,"line_end":533,"block_type":"line","text":"Client API 응답 구조로 변환","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":557,"line_end":557,"block_type":"line","text":"CCT024: 건강체 5년 내 30일이상 투약 (약효 카테고리 그루핑)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":578,"line_end":578,"block_type":"line","text":"CCT008: 건강체 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":600,"line_end":600,"block_type":"line","text":"CCT009: 건강체 5년 내 11대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":621,"line_end":621,"block_type":"line","text":"CCT010: 유병자 3개월 내","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":643,"line_end":643,"block_type":"line","text":"CCT011: 유병자 2년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":666,"line_end":666,"block_type":"line","text":"CCT012: 유병자 5년 내 입원/수술","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":688,"line_end":688,"block_type":"line","text":"CCT013: 유병자 5년 내 6대 중대질병","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":709,"line_end":709,"block_type":"line","text":"CCT014: 주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":730,"line_end":730,"block_type":"line","text":"*------------------------ 병력분석 ------------------------*//","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":732,"line_end":732,"block_type":"line","text":"CCT019: 진료로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":755,"line_end":755,"block_type":"line","text":"CCT020: 진단로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":778,"line_end":778,"block_type":"line","text":"CCT022: 투약로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":802,"line_end":802,"block_type":"line","text":"CCT023: 검사로그","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":833,"line_end":833,"block_type":"line","text":"* 1. tn_client, tn_client_contract 유효성검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/client/client.service.ts","lang":"js","line_start":842,"line_end":842,"block_type":"line","text":"* 2. client 계약 / 계약옵션 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract-admin.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"계약시작일이 계약종료일보다 클 수 없음","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract-admin.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"중복되는 계약(계약일자 범위)이 존재하는지 확인","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract-admin.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"계약시작일이 계약종료일보다 클 수 없음","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract-admin.service.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"중복되는 계약(계약일자 범위)이 존재하는지 확인","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract.service.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"고객사 계약정보 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract.service.ts","lang":"js","line_start":18,"line_end":18,"block_type":"line","text":"고객사 계약옵션 확인","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/client-contract.service.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"CI 기반 월간 분석완료 건수 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/contract.repository.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"고객사 계약정보 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/contract.repository.ts","lang":"js","line_start":144,"line_end":144,"block_type":"line","text":"CI 기반 월간 분석완료 건수 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/contract/contract.repository.ts","lang":"js","line_start":169,"line_end":169,"block_type":"line","text":"고객사 계약옵션 확인","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail-admin.service.ts","lang":"js","line_start":14,"line_end":14,"block_type":"jsdoc","text":"분석 목록조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail-admin.service.ts","lang":"js","line_start":32,"line_end":32,"block_type":"jsdoc","text":"분석 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail-admin.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.repository.ts","lang":"js","line_start":75,"line_end":75,"block_type":"jsdoc","text":"신규 주문상세 처리 및 알림톡의 사용여부 사용으로 처리 추가","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.repository.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"B2C는 ccnId가 없을 수 있으므로 선택적으로 추가","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.service.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 주문상세 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.service.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"* 주문상세 상태변경","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 주문상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/order-detail/client-order-detail.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 주문상세 조회 (고객사 정산용)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/settlement/settlement-admin.service.ts","lang":"js","line_start":13,"line_end":13,"block_type":"jsdoc","text":"고객사 정산 목록조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/settlement/settlement-admin.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"jsdoc","text":"고객사 정산 상세","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/settlement/settlement-admin.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"기업 정산 주문 목록","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/settlement/settlement-admin.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"고객사 정산 입금완료처리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/client/settlement/settlement-admin.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"jsdoc","text":"고객사 정산 입금철회처리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result-public.controller.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* AdminOptionalGuard: 관리자 admin-view(iframe) 열람 — 소유자 검증의 대체 통과 경로(req.admin)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result-public.controller.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"B2C/고객사는 memId가 없음","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.controller.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"==================== 엑셀 기능 (동적 라우트보다 먼저 선언) ====================","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.dto.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"==================== 검사기준 추천 ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* 정회원 주문(oddId)의 소유자 memId·소속 기업 agcId. 소유자/관리자 열람 검증 전용 — 없으면 null.","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"Flat 목록 조회 (대분류 + 중분류 JOIN)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"전체 카운트","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"대분류 전체 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"공백 제거 후 분류명(대분류) 중복 검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":124,"line_end":124,"block_type":"line","text":"공백 제거 후 분류항목명(중분류) 중복 검사","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":140,"line_end":140,"block_type":"line","text":"상세 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":160,"line_end":160,"block_type":"line","text":"등록 (대분류/중분류 구분하여 등록)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":165,"line_end":166,"block_type":"line","text":"대분류 등록: iscCode는 분류명(대분류), iscName은 분류항목명(중분류)\n1. 대분류 생성","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"2. 중분류도 함께 생성","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":176,"line_end":177,"block_type":"line","text":"중분류 등록: iscCode는 대분류명, iscName은 중분류명\n대분류가 이미 있는지 확인","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":183,"line_end":183,"block_type":"line","text":"대분류가 없으면 자동 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":191,"line_end":191,"block_type":"line","text":"중분류 생성","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":203,"line_end":203,"block_type":"line","text":"중분류 정보 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"중분류 이름 수정","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"대분류 이름 수정","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":233,"line_end":233,"block_type":"line","text":"삭제 (중분류 삭제 후, 대분류에 중분류가 없으면 대분류도 삭제)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":236,"line_end":236,"block_type":"line","text":"삭제할 중분류들이 속한 대분류 ID 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"중분류 삭제","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":249,"line_end":249,"block_type":"line","text":"각 대분류에 남은 중분류가 있는지 확인하고, 없으면 대분류 삭제","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"직접 필터 파라미터 처리","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":284,"line_end":284,"block_type":"line","text":"searchText 파라미터 처리 (기존 방식)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":324,"line_end":324,"block_type":"line","text":"정렬 필드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":354,"line_end":354,"block_type":"line","text":"엑셀 다운로드용 전체 목록 조회","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":373,"line_end":373,"block_type":"jsdoc","text":"임시 테이블에 백업 데이터가 존재하는지 확인","hangul_chars":19,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":385,"line_end":385,"block_type":"jsdoc","text":"Excel 업로드 처리","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":388,"line_end":388,"block_type":"line","text":"1. 임시 테이블 삭제","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":392,"line_end":392,"block_type":"line","text":"2. 현재 데이터를 임시 테이블로 백업","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":412,"line_end":412,"block_type":"line","text":"백업 데이터 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":420,"line_end":420,"block_type":"line","text":"3. 메인 테이블 전체 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":424,"line_end":424,"block_type":"line","text":"4. 신규 데이터 삽입 (대분류 먼저, 그 다음 중분류)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":429,"line_end":429,"block_type":"line","text":"중분류 삽입 (대분류 이름을 ID로 변환)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":448,"line_end":448,"block_type":"jsdoc","text":"이전 데이터 복구","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":470,"line_end":470,"block_type":"line","text":"메인 테이블 전체 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":474,"line_end":474,"block_type":"line","text":"백업 데이터로 복원","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":484,"line_end":484,"block_type":"line","text":"==================== 검사기준 추천 ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":486,"line_end":493,"block_type":"jsdoc","text":"검사기준 추천 조회\n1. tt_treat_detail에서 oddId로 조회\n2. 병원명에 '약국' 포함된 것 제외\n3. 검사명별로 총 투약일수 합산\n4. tc_clinical_result_middle, tc_clinical_result_major 조인\n5. 투약일수 내림차순 정렬","hangul_chars":49,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.repository.ts","lang":"js","line_start":494,"line_end":503,"block_type":"block","text":"[분석상세 데이터 소스 - 20260508]\n분석상세에서 원래는 tn_analysis_* 테이블을 노출해야 했으나,\n분석상세 구조 변경(1. 병력분석 탭 추가, 2. 건강체 탭 내 '5년내 7일/30일이상 투약' →\n'7일이상 진료', '30일이상 투약' 탭 분리)으로 인해 tt_treat_* 테이블을 직접 조회하게 됨.\n\ntn_analysis_* 로 보여주기 위해 PROC_COMPARE_HEALTH_RECORD, PROC_COMPARE_DOSING_RECORD,\nPROC_COMPARE_LOG 프로시저를 추가했었으나, 커넥션 풀 부족 + 분석 속도 증가 이슈로\n해당 프로시저를 사용하지 않고 tt_treat_* 테이블을 직접 조회하기로 결정됨.","hangul_chars":145,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":28,"line_end":31,"block_type":"jsdoc","text":"정회원 경로(oddId)의 소유자 검증. memId를 인자로만 받고 쓰지 않아\noddId만 바꾸면 남의 데이터가 조회됐다. B2C(bodId)/고객사(codId)는 미변경.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 관리자 admin-view(iframe) 통과 경로(2026-07): 통합관리자 전체, 기업/조직관리자는 자기 기업 건만","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"대분류 전체 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"목록 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"상세 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"공백 제거 후 중복 검사","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"대분류 등록 시 분류명(iscCode) 중복 검사","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":87,"line_end":87,"block_type":"line","text":"분류항목명(iscName)도 중복 검사","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"중분류 등록 시 분류항목명 중복 검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"현재 데이터 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"분류명(대분류) 변경 시 중복 검사 (공백 제거 후 비교)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":125,"line_end":125,"block_type":"line","text":"분류항목명(중분류) 변경 시 중복 검사 (공백 제거 후 비교)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"==================== 엑셀 기능 ====================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":148,"line_end":148,"block_type":"jsdoc","text":"엑셀 다운로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":174,"line_end":174,"block_type":"jsdoc","text":"업로드 양식 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":207,"line_end":207,"block_type":"jsdoc","text":"Excel 파일 업로드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":217,"line_end":217,"block_type":"jsdoc","text":"Excel 데이터 추출","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":234,"line_end":234,"block_type":"line","text":"헤더 스킵","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":245,"line_end":245,"block_type":"line","text":"대분류 수집 (중복 방지)","hangul_chars":9,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":248,"line_end":248,"block_type":"line","text":"중분류 추가 (필수값이므로 항상 존재)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":255,"line_end":255,"block_type":"line","text":"Set을 배열로 변환하여 대분류 데이터 생성","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":263,"line_end":263,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":269,"line_end":269,"block_type":"line","text":"대분류 중복 확인","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":283,"line_end":283,"block_type":"line","text":"중분류 중복 확인 (대분류+중분류 조합)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":302,"line_end":302,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":311,"line_end":311,"block_type":"jsdoc","text":"이전 데이터 복구","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"==================== 검사기준 추천 ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":327,"line_end":329,"block_type":"jsdoc","text":"검사기준 추천 조회","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":332,"line_end":333,"block_type":"line","text":"다른 분석 탭들(ANS001, ANS003 등)과 동일하게 구독 체크 제거\nJWT 인증만으로 데이터 조회 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":342,"line_end":344,"block_type":"jsdoc","text":"검사기준 추천 조회 (PDF용 - 권한 체크 없음)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":348,"line_end":348,"block_type":"line","text":"카테고리별로 그룹화","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/clinical-result/clinical-result.service.ts","lang":"js","line_start":371,"line_end":371,"block_type":"line","text":"Map을 배열로 변환 및 totalDay 내림차순 정렬","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.entity.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"중대질병","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.entity.ts","lang":"js","line_start":8,"line_end":8,"block_type":"line","text":"주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.entity.ts","lang":"js","line_start":9,"line_end":9,"block_type":"line","text":"숨은보험진단","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.entity.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"숨은보험치아","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.entity.ts","lang":"js","line_start":11,"line_end":11,"block_type":"line","text":"치아(틀니)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.repository.ts","lang":"js","line_start":58,"line_end":62,"block_type":"jsdoc","text":"tcCompareBasic(기본) 데이터 삭제\nttCompareBasic(임시) 데이터 선택\ntcCompareBasic(기본) 임시 데이터로 저장","hangul_chars":24,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.repository.ts","lang":"js","line_start":99,"line_end":105,"block_type":"jsdoc","text":"ttCompareBasic(임시) 삭제\ntcCompareBasic(기본) 데이터 선택\nttCompareBasic(임시) 저장\ntcCompareBasic(기본) 기존데이터 전체삭제\ntcCompareBasic(기본) 신규업로드 데이터로 저장","hangul_chars":39,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.repository.ts","lang":"js","line_start":191,"line_end":191,"block_type":"line","text":"* cpbIsSicked가 1이라면 1만, 0이라면 전부","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":49,"line_end":49,"block_type":"jsdoc","text":"목록 엑셀다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"양식 다운로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":99,"line_end":99,"block_type":"jsdoc","text":"기본데이터 업로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":127,"line_end":127,"block_type":"line","text":"* 임시데이터 존재여부 확인","hangul_chars":11,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":143,"line_end":143,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":154,"line_end":154,"block_type":"jsdoc","text":"양식 컬럼","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":164,"line_end":166,"block_type":"jsdoc","text":"엑셀 데이터 추출\nReadable.from(buffer)로 읽어올 시 한글 깨짐현상 발생","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":218,"line_end":218,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/basic/compare-basic.service.ts","lang":"js","line_start":270,"line_end":270,"block_type":"jsdoc","text":"엑셀 업로드 인터페이스","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.entity.ts","lang":"js","line_start":9,"line_end":9,"block_type":"line","text":"숨은보험치아","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.entity.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"숨은보험수술","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.entity.ts","lang":"js","line_start":11,"line_end":11,"block_type":"line","text":"숨은보험기타","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.entity.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"치아(틀니)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.repository.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"입력값의 공백을 모두 제거","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.repository.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"같은 타입의 데이터를 모두 가져옴 (수정 시 자기 자신은 제외)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.repository.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"DB의 각 데이터에서도 공백을 제거한 후 입력값과 비교","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.repository.ts","lang":"js","line_start":73,"line_end":77,"block_type":"jsdoc","text":"tcCompareBasic(기본) 데이터 삭제\nttCompareBasic(임시) 데이터 선택\ntcCompareBasic(기본) 임시 데이터로 저장","hangul_chars":24,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.repository.ts","lang":"js","line_start":112,"line_end":118,"block_type":"jsdoc","text":"ttCompareDetail(임시) 삭제\ntcCompareDetail(세부) 데이터 선택\nttCompareDetail(임시) 저장\ntcCompareDetail(세부) 기존데이터 전체삭제\ntcCompareDetail(세부) 신규업로드 데이터로 저장","hangul_chars":39,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"jsdoc","text":"목록 엑셀다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"jsdoc","text":"양식 다운로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"jsdoc","text":"세부데이터 업로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"중복 검사 (공백 제거한 값으로 비교)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"저장은 원본 그대로 (공백 포함)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"중복 검사 (공백 제거한 값으로 비교)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":136,"line_end":136,"block_type":"line","text":"저장은 원본 그대로 (공백 포함)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":145,"line_end":145,"block_type":"line","text":"* 임시데이터 존재여부 확인","hangul_chars":11,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":170,"line_end":170,"block_type":"jsdoc","text":"양식 컬럼","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":178,"line_end":180,"block_type":"jsdoc","text":"엑셀 데이터 추출\nReadable.from(buffer)로 읽어올 시 한글 깨짐현상 발생","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":201,"line_end":201,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"모든 공백을 제거한 값으로 중복 검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":242,"line_end":242,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/compare/detail/compare-detail.service.ts","lang":"js","line_start":254,"line_end":254,"block_type":"jsdoc","text":"엑셀 업로드 인터페이스","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":359,"line_end":359,"block_type":"line","text":"* 강의 책갈피 카운트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":366,"line_end":366,"block_type":"line","text":"* 강의 리뷰 평균 산출","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":378,"line_end":378,"block_type":"line","text":"* 완강이 아닌 비디오 데이터 찾기","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":453,"line_end":453,"block_type":"line","text":"* 강의 생성(ID 리턴)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":471,"line_end":471,"block_type":"line","text":"* 반복문을 통해 섹션과 강의 영상 등록","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":473,"line_end":473,"block_type":"line","text":"* 섹션 등록","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":485,"line_end":485,"block_type":"line","text":"* 해당 섹션에 대한 강의 영상 등록","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":511,"line_end":511,"block_type":"line","text":"* 강의 테이블 업데이트","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":527,"line_end":527,"block_type":"line","text":"* 현재 등록된 강의 섹션 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":541,"line_end":541,"block_type":"line","text":"* 삭제 필요 섹션 삭제 처리","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":548,"line_end":548,"block_type":"line","text":"* 전달받은 파라미터 루프 돌면서 id가 없을시 신규 있을시 수정 작업 수행","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":573,"line_end":573,"block_type":"line","text":"* 강의 영상 조회 및 처리","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":589,"line_end":589,"block_type":"line","text":"* 삭제 필요 비디오오 삭제 처리","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":596,"line_end":596,"block_type":"line","text":"* 비디오 등록/수정","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":637,"line_end":637,"block_type":"line","text":"* 마지막 시청한 영상 저장","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":649,"line_end":649,"block_type":"line","text":"* 내강의 수정일 갱신(가장 최근에 영상을 본 강의를 우선적으로 보여주기 위해서)","hangul_chars":32,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.repository.ts","lang":"js","line_start":738,"line_end":738,"block_type":"line","text":"* 유저의 경우 노출 및 미삭제 데이터 가져오게","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* 강의 목록","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.service.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 강의 목록(유저)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 강의 생성(강의, 강의 챕터, 강의영상 트리구조 형식으로 생성)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.service.ts","lang":"js","line_start":159,"line_end":159,"block_type":"jsdoc","text":"강의 신규등록 이미지 데이터","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/courses/courses.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"jsdoc","text":"s3 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/enrollments/courses-enrollments.service.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* 재생 영상 계산을 위한 로직","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.repository.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 해당 강의에 속하는 모든 영상 가져오기","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.repository.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"* 유저가 완료한 강의 영상 수 조회","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.repository.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"* 완료 비율 계산(영상수 기준으로 계산)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.service.ts","lang":"js","line_start":18,"line_end":20,"block_type":"line","text":"* 강의영상이 완료일 경우\nif (dto.crvpIsCompleted === 1) {\n  await this.coursesProgressRepository.upsertVideoProgress(memId, dto);","hangul_chars":10,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.service.ts","lang":"js","line_start":22,"line_end":25,"block_type":"line","text":"//* 해당 강의 코스 ID 획득\n  const crsId = await this.coursesProgressRepository.getCoursesIdByVideoId(\n    dto.crvId,\n  );","hangul_chars":8,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/progress/courses-progress.service.ts","lang":"js","line_start":27,"line_end":32,"block_type":"line","text":"//* 전체 영상 진척도 확인 및 완료시 저장 로직\n  return await this.coursesProgressRepository.calculateUserCoursesProgress(\n    memId,\n    crsId,\n  );\n}","hangul_chars":17,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/reviews/courses-reviews.repository.ts","lang":"js","line_start":181,"line_end":181,"block_type":"line","text":"* 강의 아이디 기준 수강평 조회","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/reviews/courses-reviews.repository.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 유저 카운트 및 총 평균 평점","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/reviews/courses-reviews.repository.ts","lang":"js","line_start":384,"line_end":384,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/courses/reviews/courses-reviews.service.ts","lang":"js","line_start":18,"line_end":18,"block_type":"line","text":"* 수강평 목록","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease-public.controller.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* AdminOptionalGuard: 관리자 admin-view(iframe) 열람 — 소유자 검증의 대체 통과 경로(req.admin)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease-public.controller.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"B2C는 memId가 없음","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease-public.controller.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"B2C는 memId가 없음","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.controller.ts","lang":"js","line_start":206,"line_end":206,"block_type":"line","text":"==================== 세세분류 ====================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.controller.ts","lang":"js","line_start":263,"line_end":263,"block_type":"line","text":"==================== 세세세분류 ====================","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"목록 조회 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"생성/수정 DTO","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":261,"line_end":261,"block_type":"line","text":"삭제 DTO - 복합키 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":501,"line_end":501,"block_type":"line","text":"계층적 필터 (새로 추가)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":558,"line_end":558,"block_type":"line","text":"검색어 필터 (변경)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":574,"line_end":574,"block_type":"line","text":"하위 호환성을 위한 기존 필드","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":612,"line_end":612,"block_type":"line","text":"프론트엔드 호환성 필드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.dto.ts","lang":"js","line_start":1166,"line_end":1166,"block_type":"line","text":"--------------------- 동일 진단코드 내원 그룹 DTO ---------------------//","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.entity.ts","lang":"js","line_start":160,"line_end":160,"block_type":"line","text":"세세분류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.entity.ts","lang":"js","line_start":211,"line_end":211,"block_type":"line","text":"세세세분류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":53,"line_end":54,"block_type":"line","text":"* 정회원 주문(oddId)의 소유자 memId. 소유자 검증 전용 — 없으면 null.\n* 정회원 주문(oddId)의 소유자 memId·소속 기업 agcId. 소유자/관리자 열람 검증 전용 — 없으면 null.","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":329,"line_end":329,"block_type":"line","text":"==================== 세세분류 (Fine Classification) ====================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":419,"line_end":419,"block_type":"line","text":"==================== 세세세분류 (Sub-Fine Classification) ====================","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":528,"line_end":528,"block_type":"line","text":"상위 코드 필터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":568,"line_end":568,"block_type":"line","text":"검색 필터","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":780,"line_end":780,"block_type":"line","text":"검색 키워드 처리 (항상 부분 일치)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":783,"line_end":783,"block_type":"line","text":"레벨 필터링: searchCondition 또는 계층적 필터에 따라 포함할 테이블 결정","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":794,"line_end":794,"block_type":"line","text":"계층적 필터가 있으면 해당 레벨 이하만 조회","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":796,"line_end":796,"block_type":"line","text":"subFineCode가 있으면 세세세분류만","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":804,"line_end":804,"block_type":"line","text":"fineCode가 있으면 세세분류와 세세세분류만","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":810,"line_end":810,"block_type":"line","text":"detailCode가 있으면 세분류 이하만","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":815,"line_end":815,"block_type":"line","text":"minorCode가 있으면 소분류 이하만","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":819,"line_end":819,"block_type":"line","text":"middleCode가 있으면 중분류 이하만","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":823,"line_end":823,"block_type":"line","text":"UNION 쿼리 빌드 - 선택된 레벨만 포함","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":948,"line_end":949,"block_type":"line","text":"정렬 처리 - 계층 구조를 유지하면서 코드 순으로 정렬\n빈 문자열('')이 알파벳보다 앞에 정렬되므로 상위 계층이 먼저 나옴","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":954,"line_end":954,"block_type":"line","text":"페이지네이션 처리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":957,"line_end":957,"block_type":"line","text":"전체 카운트 쿼리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":963,"line_end":963,"block_type":"line","text":"데이터 조회 쿼리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":991,"line_end":991,"block_type":"line","text":"분류코드 검색 - 해당 레벨의 모든 코드 컬럼에서 검색","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1017,"line_end":1017,"block_type":"line","text":"분류항목명 검색","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1020,"line_end":1020,"block_type":"line","text":"전체 검색 (코드 + 이름)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1050,"line_end":1050,"block_type":"line","text":"Flat List용 검색 조건 (항상 LIKE 사용)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1072,"line_end":1072,"block_type":"line","text":"계층적 필터 조건 (새로 추가)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1205,"line_end":1205,"block_type":"line","text":"검색 조건 처리","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1208,"line_end":1208,"block_type":"line","text":"검색 키/텍스트 조건 (새로 추가)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1337,"line_end":1337,"block_type":"line","text":"기존 검색어 조건 (하위 호환성)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1340,"line_end":1340,"block_type":"line","text":"분류코드 검색 - 해당 레벨의 모든 코드 컬럼에서 검색","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1377,"line_end":1377,"block_type":"line","text":"분류항목명 검색","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1380,"line_end":1380,"block_type":"line","text":"전체 검색 (코드 + 이름)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1409,"line_end":1409,"block_type":"line","text":"날짜 필터 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1481,"line_end":1483,"block_type":"jsdoc","text":"임시 테이블에 백업 데이터가 존재하는지 확인","hangul_chars":19,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1506,"line_end":1512,"block_type":"jsdoc","text":"Excel 업로드 처리\n1. 임시 테이블 삭제\n2. 현재 데이터를 임시 테이블로 백업\n3. 메인 테이블 삭제\n4. 신규 데이터 삽입","hangul_chars":40,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1522,"line_end":1522,"block_type":"line","text":"1. 임시 테이블 삭제","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1530,"line_end":1530,"block_type":"line","text":"2. 현재 데이터를 임시 테이블로 백업","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1607,"line_end":1607,"block_type":"line","text":"중첩 트랜잭션","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1609,"line_end":1609,"block_type":"line","text":"백업 데이터 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1629,"line_end":1629,"block_type":"line","text":"3. 메인 테이블 전체 삭제 (순서 중요: 하위 → 상위)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1637,"line_end":1637,"block_type":"line","text":"4. 신규 데이터 삽입 (순서 중요: major → middle → minor → detail → fine → subFine)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1660,"line_end":1663,"block_type":"jsdoc","text":"이전 데이터 복구\n임시 테이블의 백업 데이터를 메인 테이블로 복원","hangul_chars":27,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1743,"line_end":1743,"block_type":"line","text":"메인 테이블 전체 삭제 (순서 중요: 하위 → 상위)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1751,"line_end":1751,"block_type":"line","text":"백업 데이터로 복원 (순서 중요: 상위 → 하위)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1778,"line_end":1781,"block_type":"jsdoc","text":"tt_treat_basic에서 질병 코드들을 가져와서 계층 구조 데이터 조회 (추천보험)\n세분류, 세세분류, 세세세분류 모두에서 질병코드 검색","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1782,"line_end":1791,"block_type":"block","text":"[분석상세 데이터 소스 - 20260508]\n분석상세에서 원래는 tn_analysis_* 테이블을 노출해야 했으나,\n분석상세 구조 변경(1. 병력분석 탭 추가, 2. 건강체 탭 내 '5년내 7일/30일이상 투약' →\n'7일이상 진료', '30일이상 투약' 탭 분리)으로 인해 tt_treat_* 테이블을 직접 조회하게 됨.\n\ntn_analysis_* 로 보여주기 위해 PROC_COMPARE_HEALTH_RECORD, PROC_COMPARE_DOSING_RECORD,\nPROC_COMPARE_LOG 프로시저를 추가했었으나, 커넥션 풀 부족 + 분석 속도 증가 이슈로\n해당 프로시저를 사용하지 않고 tt_treat_* 테이블을 직접 조회하기로 결정됨.","hangul_chars":145,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1877,"line_end":1878,"block_type":"line","text":"2-0. 소분류(minor)에서 매칭되는 질병 코드로 계층 정보 조회\n세분류 이상이 등록되지 않은 코드(C19, N72 등)도 누락 없이 포함하기 위함","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1926,"line_end":1926,"block_type":"line","text":"2-1. 세분류(detail)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":1980,"line_end":1980,"block_type":"line","text":"2-2. 세세분류(fine)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2035,"line_end":2035,"block_type":"line","text":"2-3. 세세세분류(subFine)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2097,"line_end":2098,"block_type":"line","text":"3. 모든 결과 병합 (중복 제거: diseaseCode 기준)\n우선순위: detail > fine > subFine > minor (구체적인 분류 우선, findIndex 첫 매칭 사용)","hangul_chars":29,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2110,"line_end":2110,"block_type":"line","text":"4. 계층 정보에 카운트 정보 추가","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2124,"line_end":2128,"block_type":"jsdoc","text":"tt_treat_basic에서 질병 코드들을 가져와서 계층 구조 데이터 조회 (보험참고)\ntc_search_disease에서 진단코드별 보장내용을 조회하여 InsuranceComment에 포함\n세분류, 세세분류, 세세세분류 모두에서 질병코드 검색","hangul_chars":66,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2219,"line_end":2219,"block_type":"line","text":"2-0, 2-1, 2-2, 2-3 쿼리를 병렬로 실행","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2222,"line_end":2223,"block_type":"line","text":"2-0. 소분류(minor)에서 매칭되는 질병 코드로 계층 정보 조회\n세분류 이상이 등록되지 않은 코드(C19, N72 등)도 누락 없이 포함","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2268,"line_end":2268,"block_type":"line","text":"2-1. 세분류(detail)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2319,"line_end":2319,"block_type":"line","text":"2-2. 세세분류(fine)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2372,"line_end":2372,"block_type":"line","text":"2-3. 세세세분류(subFine)에서 매칭되는 질병 코드로 계층 정보 조회","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2433,"line_end":2434,"block_type":"line","text":"3. 모든 결과 병합 (중복 제거: diseaseCode 기준)\n우선순위: detail > fine > subFine > minor (구체적인 분류 우선, findIndex 첫 매칭 사용)","hangul_chars":29,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2446,"line_end":2446,"block_type":"line","text":"4. 각 레벨별 코드 수집","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2457,"line_end":2457,"block_type":"line","text":"5. tc_search_disease에서 모든 코드에 대한 보장내용 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2468,"line_end":2468,"block_type":"line","text":"6. 코드별 보장내용을 Map으로 변환","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2476,"line_end":2476,"block_type":"line","text":"7. 계층 정보에 카운트와 각 레벨별 보장내용 추가","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2485,"line_end":2485,"block_type":"line","text":"각 레벨의 코드로 개별 검색하여 해당 InsuranceComment에 적용","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2506,"line_end":2508,"block_type":"jsdoc","text":"전체 계층 구조 트리 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2510,"line_end":2510,"block_type":"line","text":"모든 데이터를 한번에 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2552,"line_end":2552,"block_type":"line","text":"트리 구조 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2592,"line_end":2594,"block_type":"jsdoc","text":"진료로그 조회 (정회원/B2C/고객사)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2597,"line_end":2597,"block_type":"line","text":"B2C 테이블 쿼리","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2617,"line_end":2617,"block_type":"line","text":"고객사 테이블 쿼리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2637,"line_end":2637,"block_type":"line","text":"정회원 테이블 쿼리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2661,"line_end":2661,"block_type":"line","text":"==================== 질병코드 → 중분류 배치 매핑 ====================","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2663,"line_end":2667,"block_type":"jsdoc","text":"질병코드 목록을 받아 중분류(middleCode, middleName)를 일괄 매핑\n우선순위: tc_disease_detail → tc_disease_fine_classification → tc_disease_sub_fine_classification\n행별 COALESCE 서브쿼리 6N개 대신 배치 쿼리 3회로 대체","hangul_chars":38,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2677,"line_end":2678,"block_type":"line","text":"우선순위(낮음→높음): minor → sub_fine → fine → detail 순으로 덮어씌워 가장 구체적인 분류가 최종 우선\n모든 비교에 COLLATE 명시 (테이블 간 collation 불일치 방지, 원본 COALESCE와 동일)","hangul_chars":49,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2684,"line_end":2684,"block_type":"line","text":"소분류(minor): 세분류 이상이 등록되지 않은 코드(C19, N72 등)도 중분류 매핑 가능하도록 포함","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2788,"line_end":2792,"block_type":"jsdoc","text":"질병코드 → 전체 분류 계층(major~subFine 코드/이름) 일괄 매핑.\n진단로그(getInsuranceReferenceTree)와 동일한 매핑 규칙으로,\nminor/detail/fine/subFine 레벨에서 매칭되는 코드의 상위 계층까지 조회한다.","hangul_chars":53,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2890,"line_end":2890,"block_type":"line","text":"세세분류(fine)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2933,"line_end":2933,"block_type":"line","text":"세세세분류(subFine)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":2986,"line_end":2986,"block_type":"line","text":"우선순위: 덜 구체적(minor)부터 set, 더 구체적(subFine)이 나중에 덮어씀","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3013,"line_end":3013,"block_type":"line","text":"==================== 5년 내 7일이상 진료 그룹 ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3015,"line_end":3019,"block_type":"jsdoc","text":"5년 내 7일이상 진료 중분류 그룹 조회 (정회원/B2C/고객사)\ntt_treat_basic에서 5년 이내 진료 기록을 중분류별로 그루핑하여\n내원일수 합계 7일 이상인 그룹만 반환","hangul_chars":55,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3021,"line_end":3025,"block_type":"line","text":"[TEMP-PROD-REVERT 2026-04-05] tt_*_treat_basic 직접 조회 (검증 완료 전까지)\n성능 최적화: 행별 COALESCE 서브쿼리 6개 → 2단계 배치 매핑으로 변환\n  Step 1: tt_treat_basic 단순 조회 (서브쿼리 없음)\n  Step 2: 유니크 질병코드만 모아 tc_disease_* 배치 조회 3회\n  Step 3: 메모리에서 중분류 매핑 조합","hangul_chars":70,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3040,"line_end":3040,"block_type":"line","text":"Step 1: tt_treat_basic 단순 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3116,"line_end":3116,"block_type":"line","text":"Step 2: 유니크 질병코드 배치 매핑 (detail → fine → sub_fine 우선순위)","hangul_chars":15,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3124,"line_end":3124,"block_type":"line","text":"Step 3: 전체 분류 계층 매핑 (중분류 매핑 실패 레코드 제외 - 기존 동작 유지)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3131,"line_end":3131,"block_type":"line","text":"7일 필터: 중분류별 내원일수 합계 7일 이상인 중분류만 노출","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3146,"line_end":3147,"block_type":"line","text":"평면 반환: 각 진료 레코드에 전체 분류 계층(중>소>세>세세>세세세) 코드/이름 부여.\n프론트(ANS003A)에서 5단계 계층 트리로 조립한다.","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3172,"line_end":3172,"block_type":"line","text":"==================== 기타 숨은보험금 그룹 (ANS009) ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3174,"line_end":3177,"block_type":"jsdoc","text":"기타 숨은보험금을 asdInEtc별로 그루핑하여 인라인 렌더링용 데이터 반환\nbasic + detail 조인, asdInEtc IS NOT NULL인 레코드만","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3271,"line_end":3271,"block_type":"line","text":"asdInEtc(숨은보험금명)별 그루핑","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3302,"line_end":3302,"block_type":"line","text":"==================== 치아 숨은보험금 그룹 (ANS007) ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3304,"line_end":3306,"block_type":"jsdoc","text":"치아 숨은보험금을 asdInTooth별로 그루핑하여 인라인 렌더링용 데이터 반환","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3434,"line_end":3434,"block_type":"line","text":"==================== 동일 진단코드 내원 그룹 ====================","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3436,"line_end":3440,"block_type":"jsdoc","text":"동일 주상병코드 내원 그룹 조회 (정회원/B2C/고객사)\ntt_treat_basic에서 5년 이내 진료 기록을 주상병코드별로 그루핑하여\n건수 2건 이상인 그룹만 반환 (약국 포함)","hangul_chars":56,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3446,"line_end":3446,"block_type":"line","text":"1. 주문 생성일 조회 및 진료 기록 조회","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3451,"line_end":3451,"block_type":"line","text":"B2C 주문 생성일 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3461,"line_end":3461,"block_type":"line","text":"B2C 5년 이내 진료 기록 조회 (약국 포함)","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3484,"line_end":3484,"block_type":"line","text":"고객사 주문 생성일 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3494,"line_end":3494,"block_type":"line","text":"고객사 5년 이내 진료 기록 조회 (약국 포함)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3517,"line_end":3517,"block_type":"line","text":"정회원 주문 생성일 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3527,"line_end":3527,"block_type":"line","text":"정회원 5년 이내 진료 기록 조회 (약국 포함)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3555,"line_end":3555,"block_type":"line","text":"2. 주상병코드별 진료 기록 그루핑","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.repository.ts","lang":"js","line_start":3588,"line_end":3588,"block_type":"line","text":"3. 2건 이상 필터 및 건수 내림차순 정렬","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":50,"line_end":54,"block_type":"jsdoc","text":"정회원 경로(oddId)의 소유자 검증.\nmemId를 인자로만 받고 쓰지 않아 oddId만 바꾸면 남의 진료이력이 조회됐다.\nB2C(bodId)/고객사(codId) 경로는 각자 인증 체계를 쓰므로 건드리지 않는다.","hangul_chars":60,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 관리자 admin-view(iframe) 통과 경로(2026-07): 통합관리자 전체, 기업/조직관리자는 자기 기업 건만","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":136,"line_end":136,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":216,"line_end":216,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":274,"line_end":274,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":298,"line_end":298,"block_type":"line","text":"프론트엔드 필드명을 DB 필드명으로 변환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":318,"line_end":318,"block_type":"line","text":"==================== 세세분류 ====================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":361,"line_end":361,"block_type":"line","text":"코드 변경이 있는지 확인","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":388,"line_end":388,"block_type":"line","text":"==================== 세세세분류 ====================","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":456,"line_end":456,"block_type":"line","text":"프론트엔드 호환성: searchText를 searchKeyword로 변환","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":461,"line_end":461,"block_type":"line","text":"프론트엔드 호환성: startDate/endDate를 createdAtFrom/createdAtTo로 변환","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":469,"line_end":469,"block_type":"line","text":"URL 인코딩된 한글을 디코딩","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":474,"line_end":474,"block_type":"line","text":"디코딩 실패 시 그대로 사용","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":478,"line_end":478,"block_type":"line","text":"searchCondition이 빈 문자열이면 'all'로 설정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":483,"line_end":483,"block_type":"line","text":"searchType이 빈 문자열이면 'all'로 설정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":496,"line_end":496,"block_type":"line","text":"1. 전체 데이터 조회 (페이지네이션 없이)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":500,"line_end":500,"block_type":"line","text":"2. Excel 워크북 생성 (stream 방식)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":504,"line_end":504,"block_type":"line","text":"3. 헤더 설정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":513,"line_end":514,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\n{ header: '추천보험', key: 'insuranceComment', width: 50 },","hangul_chars":21,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":518,"line_end":518,"block_type":"line","text":"4. 데이터 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":528,"line_end":529,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: item.insuranceComment || '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":534,"line_end":534,"block_type":"line","text":"5. 워크시트와 워크북 커밋","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":539,"line_end":539,"block_type":"jsdoc","text":"업로드 양식 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":541,"line_end":541,"block_type":"line","text":"예시 데이터","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":552,"line_end":553,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":564,"line_end":565,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":576,"line_end":577,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '감염병 관련 보험',","hangul_chars":24,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":588,"line_end":589,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":600,"line_end":601,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":612,"line_end":613,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\ninsuranceComment: '',","hangul_chars":17,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":617,"line_end":617,"block_type":"line","text":"Excel 워크북 생성 (stream 방식)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":621,"line_end":621,"block_type":"line","text":"헤더 설정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":631,"line_end":632,"block_type":"line","text":"TODO: 추천보험 항목 기능 추가 필요시 주석 해제\n{ header: '추천보험', key: 'insuranceComment', width: 50 },","hangul_chars":21,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":635,"line_end":635,"block_type":"line","text":"데이터 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":640,"line_end":640,"block_type":"line","text":"워크시트와 워크북 커밋","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":645,"line_end":645,"block_type":"jsdoc","text":"Excel 파일 업로드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":649,"line_end":649,"block_type":"line","text":"1. Excel 데이터 추출","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":652,"line_end":652,"block_type":"line","text":"2. 유효성 검사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":655,"line_end":655,"block_type":"line","text":"3. 데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":660,"line_end":660,"block_type":"jsdoc","text":"Excel 데이터 추출","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":683,"line_end":683,"block_type":"line","text":"헤더 스킵","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":689,"line_end":689,"block_type":"line","text":"필수값 체크","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":704,"line_end":704,"block_type":"line","text":"레벨별 데이터 분류","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":773,"line_end":773,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":775,"line_end":775,"block_type":"line","text":"1. 데이터 존재 여부 확인","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":787,"line_end":787,"block_type":"line","text":"2. 중복 확인 (대분류 코드)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":811,"line_end":811,"block_type":"line","text":"3. 중복 확인 (중분류 복합키)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":835,"line_end":835,"block_type":"line","text":"4. 중복 확인 (소분류 복합키)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":861,"line_end":861,"block_type":"line","text":"5. 중복 확인 (세분류 복합키)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":887,"line_end":887,"block_type":"line","text":"6. 중복 확인 (세세분류 복합키)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":913,"line_end":913,"block_type":"line","text":"7. 중복 확인 (세세세분류 복합키)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":942,"line_end":942,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":951,"line_end":952,"block_type":"line","text":"ids는 \"대:majorCode\" 또는 \"majorCode\" 형식\n또는 \"중:majorCode:middleCode\" 또는 \"majorCode-middleCode\" 형식","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":961,"line_end":961,"block_type":"line","text":"ID 파싱 및 분류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":963,"line_end":963,"block_type":"line","text":"먼저 ':'로 분리 시도 (한글 레벨 포함 형식)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":984,"line_end":984,"block_type":"line","text":"'-'로 분리 시도 (프론트엔드 generateItemId 형식)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":997,"line_end":997,"block_type":"line","text":"\"A00-A01-A001-A0001-A00011\" -> 세세분류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1000,"line_end":1000,"block_type":"line","text":"\"A00-A01-A001-A0001-A00011-A000111\" -> 세세세분류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1006,"line_end":1006,"block_type":"line","text":"그 외 단일 코드 (대분류)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1012,"line_end":1012,"block_type":"line","text":"유효하지 않은 ID가 있으면 경고 로그 출력","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1017,"line_end":1017,"block_type":"line","text":"디버깅: 파싱된 데이터 출력","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1027,"line_end":1027,"block_type":"line","text":"각 레벨별로 삭제 수행","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1068,"line_end":1068,"block_type":"jsdoc","text":"이전 데이터 복구","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1070,"line_end":1070,"block_type":"line","text":"임시 테이블에 백업 데이터 존재 여부 확인","hangul_chars":17,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1076,"line_end":1076,"block_type":"line","text":"복구 실행","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1086,"line_end":1086,"block_type":"jsdoc","text":"병명기준 추천보험 조회","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1089,"line_end":1090,"block_type":"line","text":"다른 분석 탭들(ANS001, ANS003 등)과 동일하게 구독 체크 제거\nJWT 인증만으로 데이터 조회 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1098,"line_end":1098,"block_type":"jsdoc","text":"병명기준 보험참고 트리 조회 (flat 반환 - 유저사이트/관리자 공용)","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1101,"line_end":1102,"block_type":"line","text":"다른 분석 탭들(ANS001, ANS003 등)과 동일하게 구독 체크 제거\nJWT 인증만으로 데이터 조회 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1110,"line_end":1110,"block_type":"jsdoc","text":"병명기준 보험참고 트리 조회 (트리 구조 반환 - 고객사 API 전용)","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1116,"line_end":1116,"block_type":"jsdoc","text":"병명기준 추천보험 조회 (PDF용 - 권한 체크 없음)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1119,"line_end":1119,"block_type":"line","text":"B2C는 bodId로 전달","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1124,"line_end":1124,"block_type":"jsdoc","text":"병명기준 보험참고 트리 조회 (PDF용 - 권한 체크 없음)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1127,"line_end":1127,"block_type":"line","text":"B2C는 bodId로 전달","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1129,"line_end":1129,"block_type":"line","text":"투약로그처럼 중분류 기준으로 그룹화해서 반환","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1133,"line_end":1133,"block_type":"jsdoc","text":"계층 구조 데이터를 PDF용 형식으로 변환 (대분류 기준)","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1154,"line_end":1154,"block_type":"line","text":"가장 상세한 레벨의 코드와 이름 추출","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1170,"line_end":1170,"block_type":"line","text":"majorCount 내림차순 정렬","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1182,"line_end":1182,"block_type":"jsdoc","text":"계층 구조 데이터를 PDF용 형식으로 변환 (중분류 기준 - 화면과 동일한 트리 구조)","hangul_chars":30,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1188,"line_end":1188,"block_type":"line","text":"중분류 기준 트리 구조 생성 (화면의 referenceTreeData와 동일한 구조)","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1225,"line_end":1225,"block_type":"line","text":"middleCode가 없으면 middleName으로 키 생성 (데이터가 없는 경우 건너뛰기)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1282,"line_end":1282,"block_type":"line","text":"세세분류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1301,"line_end":1301,"block_type":"line","text":"세세세분류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1322,"line_end":1322,"block_type":"line","text":"Map을 Array로 변환하고 count 기준 내림차순 정렬","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1361,"line_end":1361,"block_type":"jsdoc","text":"flat 데이터를 API 응답용 트리 구조로 변환 (사진 스펙 변수명 기준)","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1469,"line_end":1469,"block_type":"line","text":"Map → Array 변환 (사진 스펙 변수명: middleList > minorList > detailList > fineList > subFineList)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1508,"line_end":1508,"block_type":"jsdoc","text":"계층 구조 트리 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1519,"line_end":1519,"block_type":"jsdoc","text":"진료로그 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1522,"line_end":1523,"block_type":"line","text":"다른 분석 탭들(ANS001, ANS003 등)과 동일하게 구독 체크 제거\nJWT 인증만으로 데이터 조회 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1531,"line_end":1531,"block_type":"jsdoc","text":"진료로그 조회 (PDF용 - 권한 체크 없음)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1541,"line_end":1541,"block_type":"jsdoc","text":"5년 내 7일이상 진료 중분류 그룹 조회","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1551,"line_end":1551,"block_type":"line","text":"==================== 기타 숨은보험금 그룹 (ANS009) ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1553,"line_end":1553,"block_type":"jsdoc","text":"기타 숨은보험금 asdInEtc별 그룹 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1562,"line_end":1562,"block_type":"line","text":"==================== 치아 숨은보험금 그룹 (ANS007) ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1564,"line_end":1564,"block_type":"jsdoc","text":"치아 숨은보험금 asdInTooth별 그룹 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1573,"line_end":1573,"block_type":"line","text":"==================== 동일 진단코드 내원 그룹 ====================","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/disease/disease.service.ts","lang":"js","line_start":1575,"line_end":1575,"block_type":"jsdoc","text":"동일 주상병코드 내원 그룹 조회 (5년 내, 2건 이상, 약국 포함)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"searchKey/searchText 방식 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"searchKey/searchText 방식 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":109,"line_end":109,"block_type":"line","text":"상태 변환","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"회원타입 변환","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"ExcelJS Workbook 직접 사용 (스타일링 적용을 위해)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"컬럼 설정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"첫 번째 행 스타일 (머니관리와 동일)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"데이터 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-admin.controller.ts","lang":"js","line_start":237,"line_end":237,"block_type":"line","text":"attachmentFiles 배열 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"TODO: 테스트 후 20으로 원복","hangul_chars":8,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"TODO: 테스트 후 10MB로 원복","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"한글 파일명 디코딩","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"여러 인코딩 시도","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"UTF-8로 정상 디코딩되었는지 확인","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"binary로 재시도","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"파일명 디코딩 실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"디버깅 로그","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"ivhId가 없고 파일도 없으면 에러","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"TODO: 테스트 후 60으로 원복","hangul_chars":8,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"TODO: 테스트 후 10MB로 원복","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"한글 파일명 디코딩","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":139,"line_end":139,"block_type":"line","text":"파일명 디코딩 실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":168,"line_end":169,"block_type":"line","text":"파일 분배: 청구서 파일과 첨부파일 구분\n파일 순서: 청구서1, 청구서2, ..., 첨부파일1, 첨부파일2","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":174,"line_end":174,"block_type":"line","text":"각 item에 파일 매핑","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":212,"line_end":212,"block_type":"line","text":"팩스 히스토리에서 jobId 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax-user.controller.ts","lang":"js","line_start":218,"line_end":218,"block_type":"line","text":"vFax API로 상태 조회","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.dto.ts","lang":"js","line_start":99,"line_end":101,"block_type":"jsdoc","text":"배치 발송 아이템 DTO","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.dto.ts","lang":"js","line_start":125,"line_end":127,"block_type":"jsdoc","text":"배치 발송 요청 DTO","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":414,"line_end":416,"block_type":"line","text":"============================================\n배치 관련 메서드 (FAX 상태 체크용)\n============================================","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":418,"line_end":420,"block_type":"jsdoc","text":"배치 ID로 PENDING 상태인 건 수 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":434,"line_end":436,"block_type":"jsdoc","text":"배치 알림 발송 여부 확인","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":446,"line_end":448,"block_type":"jsdoc","text":"배치 결과 집계 (성공/실패 건수)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":484,"line_end":484,"block_type":"line","text":"배치의 청구인 이름 조회 (th_invoice join)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":502,"line_end":504,"block_type":"jsdoc","text":"배치 알림 발송 완료 표시","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":512,"line_end":514,"block_type":"jsdoc","text":"FAX 히스토리 상태 및 폴링 카운트 업데이트","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":537,"line_end":539,"block_type":"jsdoc","text":"FAX 코드로 히스토리 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.repository.ts","lang":"js","line_start":548,"line_end":550,"block_type":"jsdoc","text":"PENDING 상태인 FAX 히스토리 목록 조회 (상태 체크용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"receiverFax 결정: params로 받았으면 사용, 없으면 DB에서 조회","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"팩스번호 정규화: 공백, 하이픈 제거","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"FAX 설정 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"PDF 파일 페이지 수 - 프론트엔드에서 전달받은 값 우선 사용","hangul_chars":22,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":87,"line_end":87,"block_type":"line","text":"pageCount가 없으면 파일 크기 기반으로 추정","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":90,"line_end":90,"block_type":"line","text":"평균적으로 PDF 1페이지는 약 50-100KB","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":99,"line_end":112,"block_type":"line","text":"TODO: 포인트 차감 (재발송이 아닌 경우에만)\nMoneyService에 deductMoney 메서드 추가 필요\nif (!isResend) {\n  try {\n    await this.moneyService.deductMoney({\n      memId,\n      amount: pointRequired,\n      categoryCode: 'FAX_SEND',\n      description: `FAX 발송 (${receiverName})`,\n    });\n  } catch (error) {\n    throw new BadRequestException('포인트가 부족합니다.');\n  }\n}","hangul_chars":34,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"vFax API 설정이 있는 경우에만 실제 발송","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"테스트 모드도 성공으로 처리","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":144,"line_end":144,"block_type":"line","text":"팩스 발송 성공 시에만 히스토리 생성","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":148,"line_end":157,"block_type":"line","text":"TODO: 포인트 차감\nMoneyService에 deductMoney 메서드 추가 필요\nif (!isResend) {\n  await this.moneyService.deductMoney({\n    memId,\n    amount: actualPointUsed,\n    categoryCode: 'FAX_SEND',\n    description: `FAX 발송 (${receiverName})`,\n  });\n}","hangul_chars":15,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"PDF 파일을 S3에 업로드 (선택적)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"S3 업로드 실패해도 계속 진행","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":168,"line_end":170,"block_type":"line","text":"발송 성공 후 히스토리 생성\nisResend: 이 건이 \"재발송 된 적이 있는지\" 여부 (신규 생성 시 항상 false)\noriginalFxhId: 이 건이 어떤 원본을 재발송한 것인지 (재발송 건이면 원본 ID)","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":186,"line_end":186,"block_type":"line","text":"신규 생성 건은 항상 false (아직 재발송된 적 없음)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":194,"line_end":194,"block_type":"line","text":"원본 팩스 히스토리가 있으면 재발송됨으로 표시","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":228,"line_end":228,"block_type":"line","text":"CDN에서 파일 다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":245,"line_end":246,"block_type":"line","text":"1. 청구서 PDF 다운로드\nivhS3Key가 JSON 배열인지 확인 (기존 데이터 호환성)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":250,"line_end":250,"block_type":"line","text":"문자열인 경우: JSON 문자열인지 콤마로 구분된 문자열인지 확인","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"JSON 배열 문자열","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":261,"line_end":261,"block_type":"line","text":"기존 데이터: 콤마로 구분된 문자열","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":269,"line_end":269,"block_type":"line","text":"새 데이터: JSON 배열","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":278,"line_end":278,"block_type":"line","text":"CDN URL을 통한 HTTP 다운로드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":305,"line_end":305,"block_type":"line","text":"2. 첨부파일들 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":311,"line_end":311,"block_type":"line","text":"문자열인 경우: JSON 문자열인지 확인","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":316,"line_end":316,"block_type":"line","text":"첨부파일 JSON 파싱 실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":323,"line_end":323,"block_type":"line","text":"기존 데이터: 문자열 배열","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":335,"line_end":335,"block_type":"line","text":"새 데이터: 객체 배열","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":345,"line_end":345,"block_type":"line","text":"CDN URL을 통한 HTTP 다운로드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":355,"line_end":355,"block_type":"line","text":"파일 확장자에 따라 mimetype 결정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":380,"line_end":380,"block_type":"line","text":"파일이 하나도 없으면 에러","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":387,"line_end":387,"block_type":"line","text":"재발송 (머니 차감 없이)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":399,"line_end":399,"block_type":"line","text":"원본 팩스 히스토리를 재발송됨으로 표시","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":410,"line_end":412,"block_type":"jsdoc","text":"사용자 전용 FAX 재발송 (본인 검증 + 머니 차감)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":420,"line_end":420,"block_type":"line","text":"본인 FAX인지 검증","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":433,"line_end":433,"block_type":"line","text":"CDN에서 파일 다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":450,"line_end":450,"block_type":"line","text":"1. 청구서 PDF 다운로드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":501,"line_end":501,"block_type":"line","text":"2. 첨부파일 다운로드 (최대 2개)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":511,"line_end":511,"block_type":"line","text":"파싱 실패 시 무시","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":518,"line_end":518,"block_type":"line","text":"최대 2개 첨부파일만 (vFax 최대 3개 = 청구서 1개 + 첨부 2개)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":555,"line_end":555,"block_type":"line","text":"파일이 하나도 없으면 에러","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":562,"line_end":562,"block_type":"line","text":"재발송 (머니 차감 O - skipDeduction 없음)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":571,"line_end":571,"block_type":"line","text":"skipDeduction을 전달하지 않음 = 머니 차감됨","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":574,"line_end":574,"block_type":"line","text":"원본 팩스 히스토리를 재발송됨으로 표시","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":595,"line_end":602,"block_type":"line","text":"TODO: 포인트 환불\nMoneyService에 chargeMoney 메서드 추가 필요\nawait this.moneyService.chargeMoney({\n  memId: history.memId,\n  amount: history.fxhPointUsed,\n  categoryCode: 'FAX_CANCEL',\n  description: `FAX 발송 취소 환불 (${history.fxhReceiverName})`,\n});","hangul_chars":19,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":604,"line_end":604,"block_type":"line","text":"취소 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":659,"line_end":661,"block_type":"jsdoc","text":"청구서 파일 조회 (ivhId 기준)","hangul_chars":9,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":680,"line_end":680,"block_type":"line","text":"ivhS3Key 파싱 (JSON 배열 또는 문자열)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":712,"line_end":714,"block_type":"jsdoc","text":"S3에서 청구서 파일 다운로드","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":724,"line_end":726,"block_type":"jsdoc","text":"vFax 발송 상태 조회 (jobId 기준)","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":731,"line_end":733,"block_type":"jsdoc","text":"vFax 발송 취소 요청","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":738,"line_end":741,"block_type":"jsdoc","text":"여러 파일을 vFax API로 전송\n보험사 청구서 PDF(1개) + 추가 첨부파일(최대 2개) = 총 최대 3개","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":773,"line_end":773,"block_type":"line","text":"vFax는 최대 3개 파일만 지원","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":778,"line_end":778,"block_type":"line","text":"vFax API로 여러 파일 전송","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":793,"line_end":801,"block_type":"jsdoc","text":"vFax API로 여러 파일을 직접 전송\n\n플로우:\n1. 머니 차감 (skipDeduction이 아닌 경우)\n2. vFax 발송 요청\n   2-1. 실패 시: 머니 원복 + 히스토리 FAILED 생성\n   2-2. 성공 시: 히스토리 PENDING 생성 (jobId 기록)","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":826,"line_end":826,"block_type":"line","text":"FAX 설정 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":829,"line_end":829,"block_type":"line","text":"receiverFax 결정: params로 받았으면 사용, 없으면 DB에서 조회","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":850,"line_end":850,"block_type":"line","text":"팩스번호 정규화: 공백, 하이픈 제거","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":853,"line_end":853,"block_type":"line","text":"포인트 계산","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":857,"line_end":857,"block_type":"line","text":"ivhId가 있으면 청구인 이름 조회 (머니 차감 description용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":873,"line_end":874,"block_type":"line","text":"* ★보안: ivhName/secretKey 원시보간(sql.raw) → bound param. AES키가 raw SQL에 안 박히고(로그유출\n*   방지) ivhName 인젝션도 차단.","hangul_chars":25,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":884,"line_end":884,"block_type":"line","text":"청구인 이름 조회 실패 - 무시","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":888,"line_end":890,"block_type":"line","text":"============================================================\n1단계: 머니 차감 (발송 전)\n============================================================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":891,"line_end":891,"block_type":"line","text":"배치에서 전달받은 mwlId 우선 사용","hangul_chars":12,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":904,"line_end":906,"block_type":"line","text":"============================================================\n2단계: vFax 발송 요청\n============================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":925,"line_end":925,"block_type":"line","text":"테스트 모드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":928,"line_end":930,"block_type":"line","text":"============================================================\n2-1. 발송 실패 시: 머니 원복 + 히스토리 FAILED 생성\n============================================================","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":932,"line_end":932,"block_type":"line","text":"머니 원복 (차감한 경우에만)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":947,"line_end":947,"block_type":"line","text":"실패 히스토리 생성","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":971,"line_end":973,"block_type":"line","text":"============================================================\n2-2. 발송 성공 시: 히스토리 PENDING 생성\n============================================================","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":999,"line_end":999,"block_type":"line","text":"원본 팩스 히스토리가 있으면 재발송됨으로 표시","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1012,"line_end":1015,"block_type":"jsdoc","text":"배치 팩스 발송 (여러 보험사 청구서를 한 번에 발송)\n- 머니 차감을 1회만 수행하고, 각 청구서 팩스 발송은 skipDeduction으로 처리","hangul_chars":44,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1030,"line_end":1030,"block_type":"line","text":"FAX 설정 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1036,"line_end":1036,"block_type":"line","text":"1. 총 머니 계산 (각 청구서 페이지 + 첨부파일 페이지)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1037,"line_end":1037,"block_type":"line","text":"이미지는 1장, PDF는 프론트에서 계산해서 pageCount에 포함","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1039,"line_end":1039,"block_type":"line","text":"item.pageCount에는 청구서 페이지 + 첨부파일 페이지가 포함됨","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1043,"line_end":1043,"block_type":"line","text":"2. 머니 잔액 확인","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1052,"line_end":1052,"block_type":"line","text":"2-1. 청구인 이름 조회 (머니 description용)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1068,"line_end":1069,"block_type":"line","text":"* ★보안: ivhName/secretKey 원시보간(sql.raw) → bound param. AES키가 raw SQL에 안 박히고(로그유출\n*   방지) ivhName 인젝션도 차단.","hangul_chars":25,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1079,"line_end":1079,"block_type":"line","text":"청구인 이름 조회 실패 - 무시","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1083,"line_end":1083,"block_type":"line","text":"3. 머니 1회 차감 (병합)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1094,"line_end":1094,"block_type":"line","text":"4. 각 보험사별 팩스 발송 (skipDeduction: true)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1108,"line_end":1108,"block_type":"line","text":"청구서 파일과 첨부파일 합치기","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1119,"line_end":1119,"block_type":"line","text":"이미 위에서 차감됨","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1120,"line_end":1120,"block_type":"line","text":"배치 차감 wallet ID","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1131,"line_end":1131,"block_type":"line","text":"개별 발송 실패 시 해당 건 포인트만큼 부분 원복","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1166,"line_end":1168,"block_type":"line","text":"============================================================================\n스케줄러용 메서드\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1170,"line_end":1183,"block_type":"jsdoc","text":"PENDING 팩스 상태 일괄 체크 (AWS EventBridge 스케줄러에서 호출)\n\n분기1: 1시간 초과 → 발송취소 요청\n  - 취소 성공: 머니 원복 + FAILED ('대기상태가 길어 취소처리')\n  - 취소 실패 (이미 발송): 상태 조회 → 결과에 따라 처리\n  - 취소 실패 (기타): 머니 원복 + FAILED ('대기상태가 길어 취소처리')\n\n분기2: 1시간 이내 → 상태 조회\n  - SUCCESS: 히스토리 SUCCESS\n  - FAILED: 히스토리 FAILED + 사유 매핑 + 머니 원복\n  - CANCELLED (sendStatus=6): FAILED ('대기상태가 길어 취소처리') + 머니 원복\n  - PENDING (sendStatus=0,1,2): 스킵","hangul_chars":130,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1220,"line_end":1222,"block_type":"line","text":"==========================================================\n분기1: 1시간 초과 → 발송취소 요청\n==========================================================","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1229,"line_end":1229,"block_type":"line","text":"취소 성공: 머니 원복 + FAILED","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1233,"line_end":1233,"block_type":"line","text":"이미 발송된 건: 상태 조회하여 결과에 따라 처리","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1237,"line_end":1237,"block_type":"line","text":"PENDING이면 카운트 안 함 (다음 스케줄러에서 재처리)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1239,"line_end":1239,"block_type":"line","text":"기타 취소 실패: 머니 원복 + FAILED (거의 없는 케이스)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1244,"line_end":1246,"block_type":"line","text":"==========================================================\n분기2: 1시간 이내 → 상태 조회\n==========================================================","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1250,"line_end":1250,"block_type":"line","text":"PENDING이면 카운트 안 함","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1262,"line_end":1265,"block_type":"jsdoc","text":"vFax 상태 조회 결과에 따른 분기 처리\n@returns 'SUCCESS' | 'FAILED' | 'PENDING'","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1280,"line_end":1280,"block_type":"line","text":"sendStatus=3, result=G → 발송 성공","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1295,"line_end":1295,"block_type":"line","text":"sendStatus=3 + result!=G, 또는 HTTP 에러","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1302,"line_end":1302,"block_type":"line","text":"sendStatus=6 (예약취소) → 이미 취소된 상태","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1308,"line_end":1308,"block_type":"line","text":"sendStatus=0,1,2 → 아직 발송 중, 업데이트 안 함","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1318,"line_end":1320,"block_type":"jsdoc","text":"FAX 실패 처리 공통: 히스토리 FAILED 업데이트 + 머니 원복 + 배치 알림 체크","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1340,"line_end":1342,"block_type":"jsdoc","text":"FAX 실패 시 머니 환불","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1363,"line_end":1363,"block_type":"line","text":"청구인 이름 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1378,"line_end":1379,"block_type":"line","text":"* ★보안: ivhName/secretKey 원시보간(sql.raw) → bound param. AES키가 raw SQL에 안 박히고(로그유출\n*   방지) ivhName 인젝션도 차단.","hangul_chars":25,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1407,"line_end":1409,"block_type":"jsdoc","text":"배치 알림 체크 및 발송","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1427,"line_end":1427,"block_type":"line","text":"전체 성공","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1432,"line_end":1432,"block_type":"line","text":"일부 성공 (다건에서만 발생)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1435,"line_end":1435,"block_type":"line","text":"전체 실패","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fax/fax.service.ts","lang":"js","line_start":1460,"line_end":1460,"block_type":"jsdoc","text":"yyyy-MM-dd HH:mm:ss (로컬 타임존)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 회원만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":128,"line_end":131,"block_type":"line","text":"@Header(\n  'Content-Disposition',\n  `attachment;filename*=utf-8''${encodeURIComponent('기업회원목록')}.xlsx`,\n)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":139,"line_end":139,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":144,"line_end":144,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 회원만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 조직관리자(ORG)는 엑셀 다운로드도 자기 org 부분트리만","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":162,"line_end":163,"block_type":"line","text":"* 기업관리자(corp)는 자기 기업(agcId) + ORG는 org_path 부분트리 소유검증 통과분만 열람.\n*   목록은 whereClause에서 스코프되지만 단건 상세는 무방비였음(IDOR).","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":199,"line_end":199,"block_type":"line","text":"* 기업관리자(corp)는 URL 파라미터를 무시하고 자기 기업 agcId로 강제(교차 테넌트 차단).","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":463,"line_end":468,"block_type":"line","text":"@Post('resign/cancel')\n@ApiOperation({ summary: '기업FC 탈퇴철회처리' })\nasync resignCancel(@Body() body: ResignCancelAgencyFcDto) {\n  await this.agencyFcService.resignCancel(body);\n  return;\n}","hangul_chars":8,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc-admin.controller.ts","lang":"js","line_start":493,"line_end":494,"block_type":"line","text":"* 조직 설정(소속배정/조직관리자 지정)은 admin/sales 및 조직관리자에게 허용.\n*   조직관리자는 서비스에서 자기 부분트리 스코프를 검증한다.","hangul_chars":51,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":75,"line_end":78,"block_type":"line","text":"* 목록 필터: 선택 조직(orgId) 소속 회원 조회.\n*  - 기본(orgScope 미지정/self): 해당 조직만(하위 미포함) 정확 일치.\n*  - orgScope=subtree: 서비스에서 orgFilterPath로 변환해 하위 포함 조회.\n*  - 'UNASSIGNED': 미배정(org_id IS NULL) 회원만 조회.","hangul_chars":56,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* 목록 필터 내부값: orgId -> org_path LIKE prefix 변환 결과(orgScope=subtree일 때만)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"* 목록 필터 내부값: orgId='UNASSIGNED' → 미배정(org_id IS NULL) 조회 플래그","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 프론트에서 햇갈리지 않게 useAt이 1일 경우가 사용, 0일 경우가 미사용으로 처리 필요","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":136,"line_end":136,"block_type":"line","text":"* seat 하한 경고(SEAT_BELOW_CONTRACT_WARN) 무시 강행 여부 — 내부 관리자 전용.","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"* seat 하한 경고(SEAT_BELOW_CONTRACT_WARN) 무시 강행 여부 — 내부 관리자 전용.","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":192,"line_end":195,"block_type":"line","text":"* 기업조직(task-688): 신규 기업FC 등록 시 소속 조직(ULID 26자) 필수.\n*  - 단건 등록(POST /admin/agency-fc, /corp/agency-fc)은 서비스에서 누락 시 E0303 차단.\n*  - 기존 엑셀 업로드 경로는 마이그레이션 호환을 위해 누락 허용(기본 조직 자동 매핑은\n*    별도 마이그레이션 스크립트가 담당하며, 서비스 단계에서 ID 필요 시 별도 보완).","hangul_chars":98,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":201,"line_end":201,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"* seat 하한 경고(SEAT_BELOW_CONTRACT_WARN) 무시 강행 여부 — 내부 관리자 전용.","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":248,"line_end":248,"block_type":"line","text":"* 회원 소속조직 일괄 배정 요청 DTO","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.dto.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"* 조직관리자 일괄 지정/해제 요청 DTO (기업FC=MEM002 대상)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"1. 기업 FC 정보 DB 등록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"2. 등록된 FC들의 최초 구독을 처리","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"신규구독여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"3. 회원과 구독이 모두 끝난 뒤에만 성공 알림","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"1. 상태별 회원 분류(구독할 회원/해지할 회원)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"2. 구독 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"3. 해지는 전건 seat 하한을 한 번 판정한 뒤 일괄 처리","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"4. 성공/실패 분류","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.event-handler.ts","lang":"js","line_start":135,"line_end":135,"block_type":"line","text":"5. 전건 처리된 경우에만 성공 알림추가","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 조직권한 표시용","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* 최신구독상태","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":89,"line_end":89,"block_type":"line","text":"* 체험구독상품의 이용기간","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":118,"line_end":119,"block_type":"line","text":"* memId 가 corp 스코프(자기 기업 agcId + ORG는 org_path 부분트리) 안에 있는지 여부.\n*   단건 상세(getDetail) 소유검증용 — 목록 whereClause와 동일한 스코프 규칙 적용.","hangul_chars":42,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":144,"line_end":144,"block_type":"line","text":"* memId 목록이 corp 스코프(자기 기업 + ORG 부분트리) 안에 몇 건 존재하는지 반환.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":218,"line_end":218,"block_type":"line","text":"* 조직권한 표시용","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"* 최신구독상태","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":234,"line_end":234,"block_type":"line","text":"* 체험구독상품의 이용기간","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":549,"line_end":549,"block_type":"line","text":"*--------------------------- seat 하한 판정(후불정산·기업계약 변경안 3-4) ---------------------------//","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":551,"line_end":552,"block_type":"line","text":"* 판정 대상 회원의 소속 기업(agcId)과 최신 구독상태 조회.\n*   subState='구독'인 회원만 이번 요청으로 비활성화될 활성 구독으로 집계한다.","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":569,"line_end":570,"block_type":"line","text":"* 기업의 현재 활성 구독계정수 — 최신 구독상태='구독' 회원수.\n*   기업계약 상세(contract.repository)의 subscribe.count와 동일 기준.","hangul_chars":35,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":584,"line_end":585,"block_type":"line","text":"* 기업의 활성 계약(act_status='ACTIVE')에서 구독계정수 하한(act_subscription_seat) 조회.\n*   활성 계약이 없거나 seat가 NULL이면 판정 skip.","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":608,"line_end":610,"block_type":"line","text":"* 기업조직(task-688): 신규 회원 insert 시 소속 조직(orgId) 반영.\n*  - 단건 경로는 서비스가 검증·강제하므로 null이면 비어 있음을 그대로 따른다.\n*  - 엑셀 업로드는 dto.orgId 미포함 호환을 위해 undefined 허용.","hangul_chars":60,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":632,"line_end":632,"block_type":"jsdoc","text":"소속 배정 대상 회원의 memId/agcId 조회(동일 기업 검증용)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":641,"line_end":641,"block_type":"jsdoc","text":"회원 소속조직(org_id) 일괄 갱신 → 반영건수 반환","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":653,"line_end":653,"block_type":"jsdoc","text":"조직관리자 자격(mem_is_org_manager) 일괄 갱신 — 기업FC(MEM002)만 대상","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":723,"line_end":723,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":730,"line_end":730,"block_type":"line","text":"* 화면 조직 필터(기본) — 선택 조직 소속 회원만(하위 미포함, 정확 일치).","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":735,"line_end":735,"block_type":"line","text":"* 화면 조직 필터(orgScope=subtree) — 선택 조직의 부분트리(자신 포함) 회원만 조회.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":742,"line_end":742,"block_type":"line","text":"* 미배정 필터 — 소속 조직이 없는(org_id IS NULL) 회원만 조회.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/agency-fc.repository.ts","lang":"js","line_start":765,"line_end":765,"block_type":"line","text":"* 기능상 FC회원의 경우 탈퇴가 사용여부로 변경되면서 프론트에서 헷갈리지 않게 값을 0 - 탈퇴, 1 - 가입 형태로 전달받아 백엔드에서 바꿔서 처리","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* 기업조직(task-688): orgId 소속 검증을 위한 의존성.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":172,"line_end":173,"block_type":"line","text":"* 화면 조직 필터 해석 — 기본은 해당 조직만(정확 일치), orgScope=subtree면 하위 포함,\n*   orgId='UNASSIGNED'면 미배정(org_id IS NULL) 조회.","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":186,"line_end":186,"block_type":"line","text":"* 그 외에는 dto.orgId를 repository에서 정확 일치(eq) 조건으로 사용.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":189,"line_end":189,"block_type":"jsdoc","text":"기업FC 목록조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":203,"line_end":203,"block_type":"line","text":"* 소속조직 전체 경로 병합 — distinct orgId 배치 조회 후 member.orgFullPath 부여.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":222,"line_end":222,"block_type":"jsdoc","text":"기업FC 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":234,"line_end":234,"block_type":"line","text":"* 소속조직 전체 경로 병합 — 화면 목록(getAgencyFcList)과 동일하게 distinct orgId 배치 조회.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":270,"line_end":270,"block_type":"line","text":"* 화면 소속조직 표기(formatOrgCell)와 동일: 전체 경로 → 조직명 → '미배정'","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"* 화면 관리자 권한 표기와 동일","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":282,"line_end":282,"block_type":"line","text":"* 화면 '현재 플랜' 표기와 동일: 'prdCode / prdName', 없으면 '-'","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":298,"line_end":298,"block_type":"jsdoc","text":"기업FC 엑셀 양식 다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":357,"line_end":357,"block_type":"jsdoc","text":"기업FC 엑셀 업로드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":361,"line_end":361,"block_type":"line","text":"파일 존재여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":364,"line_end":364,"block_type":"line","text":"관리자정보 존재여부 (admin: admId, corp: agcId)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":372,"line_end":372,"block_type":"line","text":"기업 & 기업 계약여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":378,"line_end":378,"block_type":"line","text":"엑셀 데이터 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":384,"line_end":384,"block_type":"line","text":"유효성 검사 통과 시 이벤트 발생","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":414,"line_end":414,"block_type":"jsdoc","text":"기업FC 상세","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":419,"line_end":420,"block_type":"line","text":"* 기업관리자(corp) 접근 시 소속 기업/조직 소유검증(IDOR 차단).\n*   corp SUPER=agcId 일치, ORG=org_path 부분트리 하위여야만 열람 허용.","hangul_chars":35,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":432,"line_end":432,"block_type":"line","text":"* 소속조직 전체 경로 병합 — member.orgFullPath 부여(소속 없으면 null).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":446,"line_end":446,"block_type":"jsdoc","text":"기업 다음 구독일 계산","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":498,"line_end":498,"block_type":"jsdoc","text":"기업FC 신규등록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":500,"line_end":500,"block_type":"line","text":"관리자정보 존재여부 (admin: admId, corp: agcId)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":509,"line_end":511,"block_type":"line","text":"* 기업조직(task-688): orgId가 오면 소속 검증, 없으면 통과.\n*  - 운영은 조직 데이터 미가동(전원 미지정) + 엑셀 경로도 orgId 미포함이라\n*    orgId 강제 시 신규 등록이 전면 차단됨 → 명시됐을 때만 검증하도록 완화.","hangul_chars":68,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":522,"line_end":522,"block_type":"line","text":"기업 & 기업 계약여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":527,"line_end":527,"block_type":"line","text":"로그인아이디 & 비밀번호 유효성검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":535,"line_end":536,"block_type":"line","text":"로그인아이디 & 연락처 & 이메일 중복검사\n기업 내 중복검사로 디비에러는 아니지만 프론트 편의성을 위하여 형식통일","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":569,"line_end":569,"block_type":"line","text":"최초구독처리","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":575,"line_end":575,"block_type":"line","text":"신규구독여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":582,"line_end":586,"block_type":"jsdoc","text":"회원 소속조직 일괄 배정.\n- 대상 회원(memIds)의 org_id를 orgId로 갱신.\n- 조직과 회원의 소속 기업(agcId) 일치 검증(assertOrgBelongsToAgency 재사용).","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":594,"line_end":594,"block_type":"line","text":"* 대상 회원 조회 → 동일 기업 검증(조직과 다른 기업 회원 배정 차단).","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":602,"line_end":602,"block_type":"line","text":"* 여러 기업이 섞였거나 기업 미지정 회원 → 배정 불가.","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":606,"line_end":606,"block_type":"line","text":"* 조직-기업 일치 검증(재사용). 미존재=E0301 / 기업불일치=E0302.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":619,"line_end":622,"block_type":"jsdoc","text":"조직관리자 일괄 지정/해제.\n- 대상 회원의 mem_is_org_manager를 갱신(기업FC=MEM002만 대상).","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":635,"line_end":635,"block_type":"jsdoc","text":"기업FC 정보수정","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":649,"line_end":649,"block_type":"line","text":"로그인아이디 유효성검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":653,"line_end":653,"block_type":"line","text":"비밀번호 유효성검사","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":663,"line_end":664,"block_type":"line","text":"로그인아이디 & 연락처 & 이메일 중복검사\n기업 내 중복검사로 디비에러는 아니지만 프론트 편의성을 위하여 형식통일","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":696,"line_end":702,"block_type":"line","text":"* 사용중지/구독해지 seat 하한 판정 (후불정산·기업계약 변경안 3-4)\n*  - 대상 기업의 활성 계약(act_status='ACTIVE') seat(act_subscription_seat) 기준.\n*    seat가 NULL이거나 활성 계약이 없으면 판정 skip.\n*  - 처리 후 활성 구독계정수(현재 - 이번 요청으로 비활성화될 활성 구독 건수) < seat 이면:\n*    · 기업 관리자(role='corp') → SEAT_BELOW_CONTRACT 로 무조건 차단(force 무시).\n*    · 내부 관리자 & force 미지정 → SEAT_BELOW_CONTRACT_WARN + data { current, after, seat } (처리 안 함).\n*    · 내부 관리자 & force=true → 그대로 처리.","hangul_chars":114,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":710,"line_end":711,"block_type":"line","text":"* 이번 요청으로 비활성화될 활성 구독('구독' 상태) 건수 — 기업별 집계.\n*   s.sub_state는 tc_common 조인된 cmn_name('구독'/'해지'...) — 기존 비교 방식과 동일.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":724,"line_end":724,"block_type":"line","text":"* seat 미설정 → 판정 skip","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":731,"line_end":731,"block_type":"line","text":"* 기업 관리자는 무조건 차단 — 내부 관리자에게 요청 필요.","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":739,"line_end":739,"block_type":"line","text":"* 내부 관리자: force=true가 아니면 경고 코드 + 판정 수치 반환(처리하지 않음).","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":800,"line_end":800,"block_type":"jsdoc","text":"기업FC 탈퇴","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":803,"line_end":803,"block_type":"line","text":"* 사용중지(useAt=0)일 때만 seat 하한 판정. 사용처리(useAt=1)는 활성수가 줄지 않음.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":817,"line_end":817,"block_type":"jsdoc","text":"기업FC 탈퇴철회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":822,"line_end":822,"block_type":"jsdoc","text":"기업FC 삭제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":824,"line_end":825,"block_type":"line","text":"* 구독 중 회원 삭제도 활성 구독계정수가 줄어듦 — resign 과 동일한 seat 하한 판정.\n*   내부 관리자 전용 엔드포인트: force 미지정 시 SEAT_BELOW_CONTRACT_WARN, force=true 강행.","hangul_chars":45,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":830,"line_end":830,"block_type":"jsdoc","text":"기업FC 일괄 구독처리 엑셀 양식 다운로드","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":837,"line_end":837,"block_type":"jsdoc","text":"기존 기업FC 조직·관리자 권한 엑셀 양식 다운로드","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":902,"line_end":902,"block_type":"jsdoc","text":"기존 기업FC 계정정보 엑셀 수정 양식 다운로드","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":943,"line_end":943,"block_type":"jsdoc","text":"기존 기업FC 계정정보 엑셀 수정","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1089,"line_end":1089,"block_type":"jsdoc","text":"기존 기업FC 조직·관리자 권한 엑셀 업로드","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1154,"line_end":1154,"block_type":"jsdoc","text":"기업FC 일괄 구독처리 엑셀 업로드","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1162,"line_end":1162,"block_type":"line","text":"파일 존재여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1165,"line_end":1165,"block_type":"line","text":"관리자정보 존재여부 (admin: admId, corp: agcId)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1173,"line_end":1173,"block_type":"line","text":"기업 & 기업 계약여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1179,"line_end":1179,"block_type":"line","text":"엑셀 데이터 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1189,"line_end":1189,"block_type":"line","text":"유효성 검사 통과 시 이벤트 발생","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1245,"line_end":1245,"block_type":"jsdoc","text":"기업FC 구독처리","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1257,"line_end":1257,"block_type":"line","text":"기업 & 기업 계약여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1264,"line_end":1264,"block_type":"line","text":"구독처리할 FC 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1269,"line_end":1269,"block_type":"line","text":"기업FC 유효성검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1274,"line_end":1274,"block_type":"line","text":"3. 구독 처리 (병렬 실행)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1281,"line_end":1281,"block_type":"line","text":"4. 실패한 요청만 필터링하여 로깅","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1285,"line_end":1285,"block_type":"jsdoc","text":"기업FC 엑셀다운로드 파일명","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1296,"line_end":1296,"block_type":"jsdoc","text":"기업FC 구독 처리 - DB 풀을 잠그지 않도록 소량씩 처리","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1307,"line_end":1307,"block_type":"jsdoc","text":"개별 FC의 구독처리 - 구독 상태에 따라 신규 구독 또는 기존 구독 상태 변경","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1330,"line_end":1330,"block_type":"line","text":"해지 상태이면서 만료일이 지나지 않은 구독인지 확인","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1334,"line_end":1334,"block_type":"line","text":"만료되지 않은 해지 구독이 있는 경우 처리","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1336,"line_end":1336,"block_type":"line","text":"신규 구독인 경우 - 기존 구독 해지 후 새로운 구독 생성","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1344,"line_end":1344,"block_type":"line","text":"기존 구독 해지 처리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1349,"line_end":1349,"block_type":"line","text":"신규 구독 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1357,"line_end":1357,"block_type":"line","text":"기존 구독인 경우 - 해지 상태만 변경","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1364,"line_end":1364,"block_type":"line","text":"만료된 해지 구독이거나 구독 이력이 없는 경우 -신규 구독 생성","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1369,"line_end":1369,"block_type":"jsdoc","text":"실패한 구독 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1380,"line_end":1380,"block_type":"line","text":"실패한 구독 정보만 추출","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1388,"line_end":1388,"block_type":"line","text":"에러 출력","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1391,"line_end":1391,"block_type":"line","text":"실패한 구독 알람 메시지 생성","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1440,"line_end":1440,"block_type":"jsdoc","text":"기업FC 구독해제","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1447,"line_end":1447,"block_type":"line","text":"* 구독해지 seat 하한 판정 (후불정산·기업계약 변경안 3-4)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1451,"line_end":1451,"block_type":"line","text":"기업FC 유효성검사","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1459,"line_end":1459,"block_type":"jsdoc","text":"기업FC 구독 해지","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1471,"line_end":1471,"block_type":"jsdoc","text":"실패한 구독해지 처리","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1482,"line_end":1482,"block_type":"line","text":"실패한 구독 정보만 추출","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1490,"line_end":1490,"block_type":"line","text":"에러 출력","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1493,"line_end":1493,"block_type":"line","text":"실패한 구독 알람 메시지 생성","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1518,"line_end":1518,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1535,"line_end":1535,"block_type":"line","text":"* 화면(기업회원관리 목록) 컬럼 순서·명칭에 맞춤 — 소속조직/관리자 권한/현재 플랜 포함.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1575,"line_end":1575,"block_type":"jsdoc","text":"엑셀 양식 샘플데이터","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1608,"line_end":1608,"block_type":"jsdoc","text":"엑셀 양식 컬럼","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1621,"line_end":1621,"block_type":"jsdoc","text":"엑셀 양식 컬럼","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1629,"line_end":1629,"block_type":"jsdoc","text":"엑셀 양식 샘플데이터","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1643,"line_end":1645,"block_type":"jsdoc","text":"엑셀 데이터 추출\nReadable.from(buffer)로 읽어올 시 한글 깨짐현상 발생","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1653,"line_end":1653,"block_type":"line","text":"memLoginId와 memPassword는 필수","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1654,"line_end":1654,"block_type":"line","text":"memPassword를 제외한 모든 샘플 데이터 체크","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1685,"line_end":1687,"block_type":"jsdoc","text":"엑셀 데이터 추출\nReadable.from(buffer)로 읽어올 시 한글 깨짐현상 발생","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1695,"line_end":1695,"block_type":"line","text":"memLoginId와 subState는 필수","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1696,"line_end":1696,"block_type":"line","text":"샘플 데이터 없음","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1822,"line_end":1822,"block_type":"line","text":"헤더 행 건너뛰기","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1825,"line_end":1825,"block_type":"line","text":"필수 필드 체크","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1833,"line_end":1833,"block_type":"line","text":"샘플 데이터 체크 (\"※\" 포함 여부)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1844,"line_end":1844,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1855,"line_end":1855,"block_type":"jsdoc","text":"구독일괄 업로드 데이터 유효성 검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":1865,"line_end":1865,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2461,"line_end":2462,"block_type":"line","text":"* 기업FC 구독 유효성 검사\nTODO: 에러 메시지 수정 필요","hangul_chars":18,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2466,"line_end":2466,"block_type":"line","text":"기업FC 탈퇴상태 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2471,"line_end":2471,"block_type":"line","text":"기업FC 구독상태 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2476,"line_end":2476,"block_type":"line","text":"기업FC 계약상태 조회(= 계약중인 기업의 FC들만 구독처리 진행)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2481,"line_end":2481,"block_type":"line","text":"기업FC 상품 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2487,"line_end":2488,"block_type":"line","text":"* 기업FC 구독해지 유효성 검사\nTODO: 에러 메시지 수정 필요","hangul_chars":20,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2492,"line_end":2492,"block_type":"line","text":"기업FC 탈퇴상태 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2497,"line_end":2497,"block_type":"line","text":"기업FC 구독상태 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2505,"line_end":2505,"block_type":"jsdoc","text":"엑셀 업로드 인터페이스","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2517,"line_end":2517,"block_type":"jsdoc","text":"구독일괄 엑셀 업로드 인터페이스","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2523,"line_end":2523,"block_type":"jsdoc","text":"조직·관리자 권한 일괄 갱신 엑셀 업로드 인터페이스","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2553,"line_end":2553,"block_type":"jsdoc","text":"구독처리 요청 타입","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2562,"line_end":2562,"block_type":"line","text":"헤더 행 건너뛰기 여부","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2563,"line_end":2563,"block_type":"line","text":"필수 필드의 인덱스 배열","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/fc-agency.service.ts","lang":"js","line_start":2564,"line_end":2564,"block_type":"line","text":"샘플 데이터(\"※\") 체크가 필요한 필드의 인덱스 배열","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/subscription-batch.spec.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* 순차(BATCH_SIZE=1) — 동시 실행 최대 1건","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/agency/subscription-batch.ts","lang":"js","line_start":1,"line_end":1,"block_type":"line","text":"순차 처리 — 같은 기업 계약행 동시 업데이트로 인한 InnoDB 데드락 방지(대량 구독 일괄처리)","hangul_chars":33,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc-admin.controller.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc-admin.controller.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":77,"line_end":79,"block_type":"jsdoc","text":"toss 인증키 발급을 위한 FC id 암호화","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":106,"line_end":107,"block_type":"line","text":"* 기업조직(task-688): 소속 조직명. orgId→tn_agency_organization JOIN으로 파생.\n* LEFT JOIN 미매칭 시 null 가능 → ValidateIf로 null 통과 허용.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":115,"line_end":116,"block_type":"line","text":"* 기업조직(task-688): 조직의 ACTIVE 계약에서 파생되는 상품 ID(읽기 전용).\n* 활성 계약이 없으면 null 가능 → ValidateIf로 null 통과 허용.","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":124,"line_end":125,"block_type":"line","text":"* 기업조직(task-688): 조직의 ACTIVE 계약에서 파생되는 상품명(읽기 전용).\n* 활성 계약이 없으면 null 가능 → ValidateIf로 null 통과 허용.","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":218,"line_end":218,"block_type":"line","text":"* 기업조직(task-688): 소속 조직 변경/해제용. null은 소속 해제 의도로 허용.","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"--------------------- 추천가입내역 ---------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":233,"line_end":233,"block_type":"line","text":"--------------------- 푸시알림 설정 ---------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.dto.ts","lang":"js","line_start":312,"line_end":312,"block_type":"line","text":"--------------------- 회원푸시동의 관리 (관리자용) ---------------------//","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.entity.ts","lang":"js","line_start":61,"line_end":64,"block_type":"jsdoc","text":"소속기업 자유입력(deprecated).\ntask-688에 따라 신규 등록/수정에서는 무시되며, 표시는 [[orgName]] 사용.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.entity.ts","lang":"js","line_start":71,"line_end":72,"block_type":"line","text":"* 기업조직(task-688): 소속 조직 ID(ULID 26자). 일반/기업 회원 공통 옵셔널.\n* 수정 요청에서 null은 소속 해제 의도로 허용 → ValidateIf로 null 통과.","hangul_chars":39,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.entity.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 소속 조직명(표시용, org 조인 결과) — 조직권한 화면 현재 소속 표시","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.entity.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"* 소속 조직 전체 경로(표시용, 서비스에서 배치 병합) — 예: \"대구 > 개발팀\"","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.entity.ts","lang":"js","line_start":98,"line_end":98,"block_type":"line","text":"* 조직관리자 자격(조직권한): 1=조직관리자, 0=일반","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.module.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 기업조직(task-688): 기업FC 등록/수정 시 orgId 소속 검증에 사용.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":66,"line_end":69,"block_type":"line","text":"* 기업조직(task-688): 응답에 orgId/orgName/prdId/prdName 파생 포함.\n* orgName은 1:1 매칭이라 LEFT JOIN으로 충분.\n* prdId/prdName은 동일 조직에 ACTIVE 계약이 2건 이상일 경우\n* 행 폭증·비결정적 노출을 막기 위해 상관 서브쿼리로 최신 1건만 채택한다.","hangul_chars":64,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* 최신구독상태","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 체험구독상품의 이용기간","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":135,"line_end":135,"block_type":"line","text":"* 기업조직(task-688): 조직은 1:1 매칭이라 LEFT JOIN으로 안전. 계약/상품은 상관 서브쿼리(위)로 처리.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"* 최신구독상태","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 체험구독상품의 이용기간","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":286,"line_end":286,"block_type":"line","text":"* 엑셀다운로드에서 사용할 구독상태 (위 쿼리 삭제 시 프론트 합의 필요하기에 보류)","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":364,"line_end":366,"block_type":"line","text":"* 기업조직(task-688): memAgency는 기업회원 한정 deprecated.\n* 일반회원(MEM001)은 자유입력 호환을 위해 종전대로 갱신 허용.\n* 기업회원(MEM002)의 차단은 FcService.update에서 사전 처리.","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":371,"line_end":372,"block_type":"line","text":"* 기업조직(task-688): 소속 조직 변경/해제 반영.\n* dto에 orgId 키가 명시된 경우만 갱신(undefined는 변경 없음, null·빈문자열은 소속 해제 의도).","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":449,"line_end":449,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":582,"line_end":584,"block_type":"line","text":"------------------------- schedule -------------------------//\n* 스케줄러를 통한 탈퇴후 1년 경과시 회원 정보 삭제\n* 회원정보 삭제가 아닌 아이디 값 제외하고","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":589,"line_end":599,"block_type":"line","text":"* 탈퇴일 기준 1년 지났으며, 탈퇴여부가 탈퇴인 유저 삭제\n* MEM_TYPE에 따라 삭제처리 다르게 처리되야 하는지는 확인 필요\n* 현재 일반회원과 기업회원 둘 다 삭제 처리\nawait this.drizzle\n  .delete(tnMember)\n  .where(\n    and(\n      eq(tnMember.memIsResigned, 1),\n      lte(tnMember.memResignedAt, subDate),\n    ),\n  );","hangul_chars":61,"class":"1_policy","tags":["1_policy","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":602,"line_end":602,"block_type":"line","text":"삭제할 회원 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":615,"line_end":615,"block_type":"line","text":"회원정보 삭제","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":625,"line_end":625,"block_type":"line","text":"게시판 전화번호 초기화","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":631,"line_end":631,"block_type":"line","text":"손해사정 전화번호 초기화","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":639,"line_end":639,"block_type":"line","text":"------------------------- 추천가입내역 -------------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":690,"line_end":690,"block_type":"line","text":"------------------------- 푸시알림 설정 -------------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":726,"line_end":726,"block_type":"line","text":"------------------------- 회원푸시동의 관리 (관리자용) -------------------------//","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":786,"line_end":786,"block_type":"line","text":"날짜 검색","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":804,"line_end":804,"block_type":"line","text":"회원타입","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":814,"line_end":814,"block_type":"line","text":"영업대리점","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":823,"line_end":823,"block_type":"line","text":"영업채널","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":838,"line_end":838,"block_type":"line","text":"결제 알림 여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":843,"line_end":843,"block_type":"line","text":"분석 알림 여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.repository.ts","lang":"js","line_start":848,"line_end":848,"block_type":"line","text":"이벤트/혜택 알림 여부","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 이벤트 팝업 [다음에] 스누즈 — Redis 키 96h TTL(계정별, 웹/앱 공유·자동만료). Redis 장애 시 fail-open(계속 노출).","hangul_chars":30,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 기업조직(task-688): 회원 수정 시 orgId 검증에 사용.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"FC 유저 목록조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":59,"line_end":59,"block_type":"jsdoc","text":"FC 목록조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"jsdoc","text":"FC 목록 엑셀다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":127,"line_end":127,"block_type":"jsdoc","text":"FC 정보수정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":139,"line_end":140,"block_type":"line","text":"* 기업조직(task-688): 기업회원의 memAgency는 deprecated.\n* FE가 약속을 어기고 전송하더라도 BE가 정책을 강제하여 무시.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":144,"line_end":148,"block_type":"line","text":"* 기업조직(task-688): 기업FC 수정 시 orgId 정책 강제.\n*  - dto에 orgId가 명시되었을 때만 검증(undefined는 변경 없음).\n*  - null/빈문자열은 소속 해제 의도 → repository에서 null로 저장.\n*  - 조직 미존재 → E0301, 다른 기업 조직 → E0309(동일 기업 외 이동 차단),\n*    소속 정보 자체 불일치는 E0302.","hangul_chars":75,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":210,"line_end":210,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":251,"line_end":251,"block_type":"line","text":"*--------------------------------------------- 추천가입내역 ---------------------------------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":266,"line_end":266,"block_type":"line","text":"*--------------------------------------------- 푸시알림 설정 ---------------------------------------------//","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":269,"line_end":269,"block_type":"line","text":"* 이벤트 팝업 [다음에] 스누즈(96h) 여부 — 키 존재하면 아직 스누즈 중(웹/앱 공유).","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":279,"line_end":279,"block_type":"line","text":"* [다음에] — 96시간 스누즈 세팅(계정별). Redis 없으면 무동작(계속 노출 = fail-open).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fc/fc.service.ts","lang":"js","line_start":292,"line_end":292,"block_type":"line","text":"*--------------------------------------------- 회원푸시동의 관리 (관리자용) ---------------------------------------------//","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fcm/fcm.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"딥링크 URL 결정: 링크 타입이면 redirectUri, 아니면 상세 페이지","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fcm/fcm.service.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"기존 필드 (하위 호환성 유지)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fcm/fcm.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"새 딥링크 필드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fcm/fcm.service.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"* 해당 에러 전파로 인해 이후 프로세스에 영향가지 않도록 토큰만 삭제 조치","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/fcm/fcm.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 유효하지 않은 토큰 삭제 조치","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.controller.ts","lang":"js","line_start":11,"line_end":11,"block_type":"line","text":"* 기관 사용중지 안내(팝업 정보)는 정회원/B2C 비로그인 진입 화면에서 모두 조회해야 하므로 인증 가드 미적용","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 관리자 — 수정요청 (multipart 의 institutionBlockData JSON 형태)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* DB update 시 이미지 컬럼만 분리한 형태","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"* 관리자 상세 응답 (raw값 그대로 반환)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"* 관리자 목록 응답 - 2건(HIRA, NTS) 평탄 배열","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 유저 화면 — 사용중지 여부/팝업 안내 응답","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.dto.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* 유저 화면 — 경로 파라미터","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.entity.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 기관 코드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.entity.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"* 사용중지 안내 팝업 타입 (popup 도메인과 동일한 코드 체계)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.exception.ts","lang":"js","line_start":4,"line_end":5,"block_type":"line","text":"* 기관 사용중지 상태에서 신규분석이 요청된 경우 사용\n* CodefException과 동일한 형태로 503 응답을 만들어 프론트가 팝업으로 처리","hangul_chars":45,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 관리자 - 전체 목록 (HIRA, NTS 2건)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"* 관리자 - 단건 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* 관리자 - 수정 (multipart: 이미지 + JSON)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* cross-field 검증: 기간 역전, 이미지 팝업의 이미지 누락","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":78,"line_end":79,"block_type":"line","text":"* 사용중지 활성(isbBlocked=1) + 기간 둘 다 존재할 때 startedAt < endedAt 강제\n* (isActiveBlock 이 기간 역전 시 조용히 false 로 떨어져 차단이 무력화되는 것을 사전 차단)","hangul_chars":43,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"* 이미지 팝업타입일 때 요청 JSON 의 isbImg 또는 첨부 파일 중 하나는 반드시 존재","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":97,"line_end":98,"block_type":"line","text":"* 텍스트 팝업타입일 때 제목/내용 중 최소 하나는 반드시 존재\n* (이미지 팝업 검증과 같은 정책 — 저장 시점에 강제해야 추후 isbBlocked 토글만으로 켰을 때 빈 팝업 노출이 방지됨)","hangul_chars":64,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* 유저 - 현재 차단 상태 + 팝업 정보 조회","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 진입점 가드 — 차단 중이면 InstitutionBlockException throw","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 차단 활성 여부: isbBlocked=1 AND (시작/종료 기간이 비었거나 현재 시각이 범위 안)","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/institution-block/institution-block.service.ts","lang":"js","line_start":197,"line_end":197,"block_type":"line","text":"* 파일 미첨부: 요청 JSON 의 isbImg 우선, 누락(undefined) 시 기존 키 보존","hangul_chars":18,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"팩스타입에 따른 필수값 검증","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"팩스 발송 한도 대비: 양식 용량 초과 시 압축(동의 시) 후 업로드","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"S3 성공 후 DB 저장, 실패 시 S3 파일 삭제 (보상 트랜잭션)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"DB 저장 실패 시 S3 파일 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":57,"line_end":59,"block_type":"jsdoc","text":"팩스타입에 따른 필수 필드 검증","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"고정팩스: 팩스번호 필수","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"가상팩스: 관리자 입력 없음 (사용자가 직접 입력)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"다중팩스: 팩스 목록 필수","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"각 항목의 팩스번호 검증 및 중복 체크","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":96,"line_end":101,"block_type":"jsdoc","text":"양식 PDF 업로드 버퍼 결정.\n - 한도 이하: 원본 그대로.\n - 초과 + compress 미동의: NEED_COMPRESS 던져 프론트가 \"압축할까요?\" 묻게 함.\n - 초과 + compress 동의: ghostscript 압축 후 반환. 압축 후에도 초과면 실패.","hangul_chars":56,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"팩스타입에 따른 필수값 검증 (팩스타입이 변경된 경우 또는 관련 필드가 있는 경우)","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":143,"line_end":143,"block_type":"line","text":"S3 작업 먼저 수행","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":145,"line_end":145,"block_type":"line","text":"파일 변경: 용량 초과 시 압축(동의 시) 후 업로드. 코드도 바뀌면 새 키로.","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"코드만 변경: 파일 복사 후 삭제","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":153,"line_end":153,"block_type":"line","text":"S3 성공 후 DB 업데이트","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"DB 업데이트 실패 시 S3 변경사항 롤백","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"새로 업로드한 파일 삭제","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"이름 변경 롤백: 다시 원래 이름으로 변경","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"파일만 변경된 경우는 롤백 불가 (원본 파일 없음)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice-admin.service.ts","lang":"js","line_start":169,"line_end":169,"block_type":"line","text":"DB 성공 후 구 파일 삭제 및 캐시 무효화","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":33,"line_end":35,"block_type":"line","text":"* 가드가 없어 비로그인 상태에서 ivhId만 바꾸면 남의 청구서/PDF가 그대로 열렸다.\n* merged-pdf는 어드민(팩스 사용내역)만 쓰므로 관리자 가드로 따로 보호한다 —\n* 클래스 레벨에 회원 가드를 두면 관리자 토큰이 막히므로 라우트별로 명시한다.","hangul_chars":87,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"* 조회 대상은 토큰으로만 정한다(클라 전송 memId 무시).","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"Base64로 인코딩하여 JSON 응답 (원본 파일명 포함)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 관리자 가드로 이미 인증됨 → 소유자 제한 없이 조회(어드민 팩스 사용내역).","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":145,"line_end":146,"block_type":"line","text":"FormData에서 데이터 파싱\nrequestedInvoices는 이미 배열로 들어옴","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":151,"line_end":151,"block_type":"line","text":"insurerNames 파싱 (보험사명 배열)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"* 소유자는 토큰으로만 정한다. 클라 전송 memId를 쓰면 남의 계정으로 청구서가 생성된다.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":169,"line_end":169,"block_type":"line","text":"모든 파일을 청구서 PDF로 저장 (보험사별로 여러 개)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.controller.ts","lang":"js","line_start":183,"line_end":183,"block_type":"line","text":"fileNames 배열 파싱 (프론트에서 전달한 원본 파일명)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.drawer.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"주민등록번호","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"팩스 발송 가능 여부 플래그 추가","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":220,"line_end":220,"block_type":"line","text":"고정팩스: 팩스번호가 있어야 발송 가능","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":225,"line_end":225,"block_type":"line","text":"가상팩스: 사용자가 직접 입력하므로 항상 발송 가능","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":229,"line_end":229,"block_type":"line","text":"다중팩스: 팩스 목록이 있어야 발송 가능","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":234,"line_end":234,"block_type":"line","text":"기존 FAX 타입 호환 (마이그레이션 전)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":246,"line_end":246,"block_type":"line","text":"* 청구서 이력의 소유자(memId). 소유자 검증 전용 — 없으면 null.","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":266,"line_end":266,"block_type":"line","text":"레코드가 없는 경우 빈 데이터 반환","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"팩스 발송 내역 조회 (원본만, 재발송 아닌 것만)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":297,"line_end":297,"block_type":"line","text":"각 팩스에 대한 재발송 내역 조회","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":325,"line_end":326,"block_type":"line","text":"ivhInsurers는 이미 보험사 상세 정보를 JSON 배열로 가지고 있음\n[{\"insCode\": \"...\", \"insName\": \"...\", \"insFaxNumber\": \"...\"}]","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":388,"line_end":388,"block_type":"line","text":"각 레코드에 팩스 히스토리 추가","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":391,"line_end":391,"block_type":"line","text":"보험사 정렬","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":395,"line_end":395,"block_type":"line","text":"팩스 히스토리 조회 (faxCode 포함)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":444,"line_end":445,"block_type":"line","text":"* ★보안(SQLi): requestedInvoices는 dto(사용자입력). 전엔 `'${value}'` 문자열로 만들어 sql.raw로\n*   IN절에 보간 → 인젝션. drizzle sql.join으로 각 값을 bound param(?)으로 바인딩한다.","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":561,"line_end":561,"block_type":"line","text":"가상팩스로 변경 시 고정팩스번호 초기화","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":598,"line_end":600,"block_type":"jsdoc","text":"30일 이상 경과된 청구서 조회 (S3 파일이 있는 경우만)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":622,"line_end":624,"block_type":"jsdoc","text":"청구서의 S3 키 필드를 NULL로 초기화","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.repository.ts","lang":"js","line_start":635,"line_end":637,"block_type":"jsdoc","text":"기존 청구서 데이터의 ivhInsurers에 insFaxType, insFaxList 추가","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":63,"line_end":66,"block_type":"jsdoc","text":"청구서 이력 소유자 검증. ivhId만 바꿔 남의 청구서(피보험자명·연락처·진료내역)를\n조회/다운로드할 수 있어 추가한다. 토큰이 없으면 viewerMemId가 -1이라 항상 차단된다.","hangul_chars":60,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* null = 관리자 경로(이미 관리자 가드로 인증됨) → 소유자 제한 없음.","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"각 히스토리의 팩스 상태를 vFax API로 실시간 조회","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"각 팩스 히스토리의 실시간 상태 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"vFax API로 실시간 상태 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"3초 타임아웃","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"vFax API에서 받은 실시간 상태 (0,1,2,3,5,6)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"vFax API 조회 실패 시 DB 상태 그대로 사용","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"th_invoice 테이블에서 s3Key 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"ivhS3Key가 JSON 배열인지 확인","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":158,"line_end":158,"block_type":"line","text":"문자열인 경우: JSON 문자열인지 콤마로 구분된 문자열인지 확인","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":160,"line_end":160,"block_type":"line","text":"JSON 배열 문자열","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"기존 데이터: 콤마로 구분된 문자열 -> 확장자만 추출","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":178,"line_end":178,"block_type":"line","text":"새 데이터: JSON 배열 (Drizzle이 자동 파싱)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":184,"line_end":187,"block_type":"line","text":"보험사 목록(ivhInsurers) 순서에 맞춰 청구서 PDF 묶음을 재정렬.\nWhy: 클라이언트는 보험사 배열과 PDF 배열을 같은 인덱스로 짝지어 발송 요청을 만드는데\n(FaxSendPage.tsx), 저장된 PDF 순서(ivhS3Key)가 보험사 목록 순서(ivhInsurers)와\n다를 경우 잘못된 보험사로 청구서가 발송된다 (2026-05 사고).","hangul_chars":87,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":208,"line_end":208,"block_type":"line","text":"매핑되지 않은 PDF(보험사명이 목록에 없거나 파싱 실패)는 원래 순서대로 뒤에 추가","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"CDN에서 여러 PDF 다운로드 (보험사별)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":226,"line_end":226,"block_type":"line","text":"PDF 다운로드 실패 시 계속 진행","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"첨부파일들도 다운로드 (ivh_attachment_s3_keys)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":237,"line_end":237,"block_type":"line","text":"문자열인 경우: JSON 문자열인지 확인","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":242,"line_end":242,"block_type":"line","text":"첨부파일 JSON 파싱 실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":249,"line_end":249,"block_type":"line","text":"기존 데이터: 문자열 배열 -> 확장자만 추출","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"line","text":"새 데이터: 객체 배열","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":271,"line_end":271,"block_type":"line","text":"첨부파일 다운로드 실패","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":285,"line_end":289,"block_type":"jsdoc","text":"특정 보험사의 청구서 + 첨부파일을 병합한 PDF 반환\n@param ivhId 청구서 발급 내역 ID\n@param insurerName 보험사명 (옵션, 없으면 첫번째 청구서)","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":295,"line_end":295,"block_type":"line","text":"* 소유자 검증은 getHistoryPdf 내부에서 수행된다.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":302,"line_end":302,"block_type":"line","text":"병합할 청구서 PDF 선택 (보험사명으로 찾거나 첫번째)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":318,"line_end":318,"block_type":"line","text":"PDF 병합 시작","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":321,"line_end":321,"block_type":"line","text":"1. 청구서 PDF 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":326,"line_end":326,"block_type":"line","text":"2. 첨부파일 추가 (PDF와 이미지)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":332,"line_end":332,"block_type":"line","text":"PDF 파일인지 확인 (PDF 시그니처 확인)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":344,"line_end":344,"block_type":"line","text":"이미지 파일을 PDF 페이지로 변환하여 추가","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":346,"line_end":346,"block_type":"line","text":"PNG, JPEG 이미지를 PDF에 임베드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":355,"line_end":355,"block_type":"line","text":"지원하지 않는 이미지 형식","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":359,"line_end":359,"block_type":"line","text":"이미지를 페이지에 추가","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":363,"line_end":363,"block_type":"line","text":"페이지 크기를 이미지에 맞추거나, A4 크기로 조정","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":381,"line_end":381,"block_type":"line","text":"첨부파일 병합 실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":385,"line_end":385,"block_type":"line","text":"병합된 PDF를 Buffer로 변환","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":398,"line_end":398,"block_type":"line","text":"먼저 히스토리 생성하여 ivhId 획득","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":402,"line_end":402,"block_type":"line","text":"여러 PDF 버퍼를 S3에 업로드 (보험사별)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":427,"line_end":427,"block_type":"line","text":"S3 키 업데이트 (청구서 PDF 배열로 저장)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":449,"line_end":449,"block_type":"line","text":"프론트에서 전달한 원본 파일명 사용 (없으면 file.originalname 사용)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/invoice.service.ts","lang":"js","line_start":465,"line_end":465,"block_type":"line","text":"DB 업데이트","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/pdf.util.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 팩스 발송 한도(vFax 실측 ~7MiB) 대비 안전 목표치. 양식이 이보다 크면 압축 안내.","hangul_chars":27,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/invoice/pdf.util.ts","lang":"js","line_start":9,"line_end":13,"block_type":"jsdoc","text":"스캔 이미지 PDF를 ghostscript로 다운샘플 압축한다.\n - pdf-lib로는 임베드 이미지 재인코딩이 안 돼 ghostscript에 위임(런타임에 gs 필요).\n - 실패(gs 미설치 등) 시 원본 버퍼를 그대로 반환하지 않고 throw → 호출부에서 사유 노출.","hangul_chars":69,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"* 새로운 카테고리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 갱신이 필요한 카테고리","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 삭제 된 카테고리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 상위 카테고리 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":156,"line_end":156,"block_type":"line","text":"* 하위 카테고리 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":168,"line_end":168,"block_type":"line","text":"* 신규 카테고리 추가","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":180,"line_end":180,"block_type":"line","text":"* 삭제된 카테고리 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.repository.ts","lang":"js","line_start":201,"line_end":201,"block_type":"line","text":"* 하위 카테고리 목록 조회(상위 카테고리 ID 기준)","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.service.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"* 카테고리 삭제(해당 id값 기준으로 부모 id값을 가진 데이터도 삭제)","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment-category/loss-adjustment-category.service.ts","lang":"js","line_start":57,"line_end":57,"block_type":"line","text":"* 하위 카테고리 목록","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* 손해사정서비스 목록","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":101,"line_end":101,"block_type":"line","text":"* 손해사정서비스 목록","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"* 손해사정서비스 상세","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"* 손해사정서비스 생성","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":195,"line_end":195,"block_type":"line","text":"* 첨부파일이 있을 시","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":218,"line_end":218,"block_type":"line","text":"* 손해사정서비스 수정(현재 상태가 대기상태일 경우에만 가능)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"* 삭제할 파일 ID 확인 후 삭제","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":245,"line_end":245,"block_type":"line","text":"* 새로 저장이 필요한 파일이 있을 경우","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":268,"line_end":268,"block_type":"line","text":"* 손해사정서비스 삭제(현재 사용할지 모르는 상황)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":294,"line_end":294,"block_type":"line","text":"* 손해사정서비스 목록","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.repository.ts","lang":"js","line_start":367,"line_end":367,"block_type":"line","text":"* 관리자자","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"* 손해사정 서비스 목록 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"* 손해사정 관리자 목록 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 손해사정 미응답 목록 조회","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 손해사정 서비스 상세","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"* 손해사정 서비스 신규 등록","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"* 손해사정서비스 수정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/loss-adjustment/loss-adjustment/loss-adjustment.service.ts","lang":"js","line_start":131,"line_end":131,"block_type":"line","text":"* 손해사정서비스 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"글씨 굵게, 크기 설정, 흰색","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"가운데 정렬","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":83,"line_end":83,"block_type":"line","text":"파란색 배경","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"숫자 포맷 설정","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":105,"line_end":105,"block_type":"line","text":"글씨 굵게, 크기 설정, 흰색","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":106,"line_end":106,"block_type":"line","text":"가운데 정렬","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medical/medical.service.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"파란색 배경","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard-public.controller.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* AdminOptionalGuard: 관리자 admin-view(iframe) 열람 — 소유자 검증의 대체 통과 경로(req.admin)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard-public.controller.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"B2C/고객사는 memId가 없음","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.controller.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"==================== 엑셀 기능 (동적 라우트보다 먼저 선언) ====================","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"A-1. 대분류 목록 조회 Response","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"B-1. 중분류 목록 조회 (페이지네이션 + 필터)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"개별 필터 필드 (프론트엔드 호환)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"B-2. 중분류 상세 조회 Response","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"B-3. 중분류 등록","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"B-4. 중분류 수정","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":204,"line_end":204,"block_type":"line","text":"B-5. 중분류 삭제 (일괄)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":212,"line_end":212,"block_type":"line","text":"==================== C. 투약기준 추천 API ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":214,"line_end":214,"block_type":"line","text":"C-1. 투약기준 추천 조회 Request","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":250,"line_end":250,"block_type":"line","text":"C-2. 투약기준 추천 항목","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":271,"line_end":271,"block_type":"line","text":"C-2-1. 투약기준 카테고리 (그룹화된 데이터)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":290,"line_end":290,"block_type":"line","text":"C-3. 투약기준 추천 조회 Response","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":305,"line_end":305,"block_type":"line","text":"==================== D. 5년 내 30일이상 투약 그룹 API ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":317,"line_end":317,"block_type":"line","text":"D-2. 처방 기록 항목","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":353,"line_end":353,"block_type":"line","text":"D-2-1. 30일이상 투약 카테고리 그룹 항목","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.dto.ts","lang":"js","line_start":377,"line_end":377,"block_type":"line","text":"D-3. 30일이상 투약 그룹 조회 Response","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 정회원 주문(oddId)의 소유자 memId·소속 기업 agcId. 소유자/관리자 열람 검증 전용 — 없으면 null.","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"공백 제거 후 분류명(대분류) 중복 검사","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"공백 제거 후 분류항목명(mscCode) 중복 검사","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":227,"line_end":227,"block_type":"line","text":"1. 삭제할 투약기준들이 속한 카테고리 ID 조회","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":235,"line_end":235,"block_type":"line","text":"2. 투약기준 삭제","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":240,"line_end":240,"block_type":"line","text":"3. 각 카테고리에 남은 투약기준이 있는지 확인하고, 없으면 카테고리 삭제","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":256,"line_end":256,"block_type":"line","text":"==================== 검색 조건 빌더 ====================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"대분류 필터","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":265,"line_end":265,"block_type":"line","text":"개별 필드 필터 (프론트엔드 직접 호출)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"검색 필터 (searchKey + searchText 조합)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":291,"line_end":291,"block_type":"line","text":"날짜 필터","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":328,"line_end":328,"block_type":"line","text":"기본 정렬: 대분류 ID → 중분류 ID 오름차순","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":337,"line_end":337,"block_type":"jsdoc","text":"엑셀 다운로드용 전체 목록 조회","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":357,"line_end":357,"block_type":"jsdoc","text":"임시 테이블에 백업 데이터가 존재하는지 확인","hangul_chars":19,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":369,"line_end":369,"block_type":"jsdoc","text":"Excel 업로드 처리","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":372,"line_end":372,"block_type":"line","text":"1. 임시 테이블 삭제","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":376,"line_end":376,"block_type":"line","text":"2. 현재 데이터를 임시 테이블로 백업","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":396,"line_end":396,"block_type":"line","text":"백업 데이터 저장 (원시 SQL 사용)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":410,"line_end":410,"block_type":"line","text":"3. 메인 테이블 전체 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":414,"line_end":414,"block_type":"line","text":"4. 신규 데이터 삽입 (대분류 먼저, 그 다음 중분류)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":419,"line_end":419,"block_type":"line","text":"중분류 삽입 (대분류 이름을 ID로 변환)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":439,"line_end":439,"block_type":"jsdoc","text":"이전 데이터 복구","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":461,"line_end":461,"block_type":"line","text":"메인 테이블 전체 삭제","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":465,"line_end":465,"block_type":"line","text":"백업 데이터로 복원 (원시 SQL 사용)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":481,"line_end":481,"block_type":"line","text":"==================== 투약기준 추천 ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":483,"line_end":490,"block_type":"jsdoc","text":"투약기준 추천 조회\n1. tt_treat_prescribe에서 oddId로 조회\n2. 병원명에 '약국' 포함된 것 제외\n3. 약명별로 총 투약일수 합산\n4. tc_medication_standard, tc_medication_category 조인\n5. 투약일수 내림차순 정렬","hangul_chars":48,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":491,"line_end":500,"block_type":"block","text":"[분석상세 데이터 소스 - 20260508]\n분석상세에서 원래는 tn_analysis_* 테이블을 노출해야 했으나,\n분석상세 구조 변경(1. 병력분석 탭 추가, 2. 건강체 탭 내 '5년내 7일/30일이상 투약' →\n'7일이상 진료', '30일이상 투약' 탭 분리)으로 인해 tt_treat_* 테이블을 직접 조회하게 됨.\n\ntn_analysis_* 로 보여주기 위해 PROC_COMPARE_HEALTH_RECORD, PROC_COMPARE_DOSING_RECORD,\nPROC_COMPARE_LOG 프로시저를 추가했었으나, 커넥션 풀 부족 + 분석 속도 증가 이슈로\n해당 프로시저를 사용하지 않고 tt_treat_* 테이블을 직접 조회하기로 결정됨.","hangul_chars":145,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":588,"line_end":588,"block_type":"line","text":"==================== 5년 내 30일이상 투약 그룹 ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":590,"line_end":596,"block_type":"jsdoc","text":"5년 내 30일이상 투약 카테고리 그룹 조회\n1. 주문 상세의 생성일 기준 5년 필터\n2. 처방 데이터를 약효 카테고리별로 그루핑하여 투약일수 합산\n3. 30일 이상인 카테고리만 필터\n4. 각 카테고리의 진료 기록(약국 제외) 조회","hangul_chars":80,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.repository.ts","lang":"js","line_start":770,"line_end":770,"block_type":"line","text":"진료시작일 최신순 정렬 (최신 → 오래된)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":28,"line_end":31,"block_type":"jsdoc","text":"정회원 경로(oddId)의 소유자 검증. memId를 인자로만 받고 쓰지 않아\noddId만 바꾸면 남의 데이터가 조회됐다. B2C(bodId)/고객사(codId)는 미변경.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 관리자 admin-view(iframe) 통과 경로(2026-07): 통합관리자 전체, 기업/조직관리자는 자기 기업 건만","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"공백 제거 후 중복 체크","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"공백 제거 후 분류항목명(mscCode) 중복 검사","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"현재 데이터 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"분류항목명(mscCode) 변경 시 중복 검사 (공백 제거 후 비교)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"==================== 엑셀 기능 ====================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":153,"line_end":153,"block_type":"jsdoc","text":"엑셀 다운로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":181,"line_end":181,"block_type":"jsdoc","text":"업로드 양식 다운로드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":218,"line_end":218,"block_type":"jsdoc","text":"Excel 파일 업로드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":235,"line_end":235,"block_type":"jsdoc","text":"Excel 데이터 추출","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"헤더 스킵","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":264,"line_end":264,"block_type":"line","text":"대분류 수집 (중복 방지)","hangul_chars":9,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":267,"line_end":267,"block_type":"line","text":"중분류 데이터 추가","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"Set을 배열로 변환하여 대분류 데이터 생성","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":283,"line_end":283,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":289,"line_end":289,"block_type":"line","text":"대분류 중복 확인","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":303,"line_end":303,"block_type":"line","text":"중분류 중복 확인 (코드 기준)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":320,"line_end":320,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":330,"line_end":330,"block_type":"line","text":"==================== 5년 내 30일이상 투약 그룹 ====================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":332,"line_end":332,"block_type":"jsdoc","text":"5년 내 30일이상 투약 카테고리 그룹 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":338,"line_end":338,"block_type":"jsdoc","text":"이전 데이터 복구","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":352,"line_end":352,"block_type":"line","text":"==================== 투약기준 추천 ====================","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":354,"line_end":354,"block_type":"jsdoc","text":"투약기준 추천 조회","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":357,"line_end":358,"block_type":"line","text":"다른 분석 탭들(ANS001, ANS003 등)과 동일하게 구독 체크 제거\nJWT 인증만으로 데이터 조회 가능","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":367,"line_end":367,"block_type":"jsdoc","text":"투약기준 추천 조회 (PDF용 - 권한 체크 없음)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":371,"line_end":371,"block_type":"line","text":"카테고리별로 그룹화","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/medication-standard/medication-standard.service.ts","lang":"js","line_start":396,"line_end":396,"block_type":"line","text":"Map을 배열로 변환 및 totalDay 내림차순 정렬","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.controller.ts","lang":"js","line_start":12,"line_end":14,"block_type":"jsdoc","text":"전체 메뉴 트리 조회 (권한 설정용)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.controller.ts","lang":"js","line_start":22,"line_end":24,"block_type":"jsdoc","text":"내 권한에 맞는 메뉴 트리 조회 (사이드바용)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.repository.ts","lang":"js","line_start":10,"line_end":12,"block_type":"jsdoc","text":"전체 메뉴 조회 (권한 설정용)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.repository.ts","lang":"js","line_start":28,"line_end":31,"block_type":"jsdoc","text":"관리자 권한 기반 메뉴 조회 (사이드바용)\n권한이 있는 메뉴 + 부모 메뉴를 함께 조회","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.repository.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"1. 관리자가 권한을 가진 메뉴 ID 목록 조회","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.repository.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"2. 권한 있는 메뉴 ID와 부모 메뉴 ID 수집","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.repository.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"3. 권한 있는 메뉴 + 부모 메뉴 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.service.ts","lang":"js","line_start":8,"line_end":10,"block_type":"jsdoc","text":"전체 메뉴 트리 조회 (권한 설정용)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.service.ts","lang":"js","line_start":16,"line_end":18,"block_type":"jsdoc","text":"관리자의 권한에 맞는 메뉴 트리 반환 (사이드바용)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.service.ts","lang":"js","line_start":24,"line_end":26,"block_type":"jsdoc","text":"플랫 메뉴 목록을 트리 구조로 변환","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.service.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"1단계: 모든 메뉴를 Map에 등록","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/menu/menu.service.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"2단계: 부모-자식 관계 구성","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":68,"line_end":69,"block_type":"line","text":"* 보안갭 보강: 기존 RolesGuard/@Roles 부재로 corp JWT 무제한 통과 → admin/sales로 제한.\n*   (corp 는 회원머니 내역 조회만 별도 허용 — 아래 wallet 목록/엑셀. 기업머니 풀잔액(th_money_corp)은 제외)","hangul_chars":48,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":76,"line_end":78,"block_type":"line","text":"============================================================================\n회원머니 관리\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":83,"line_end":85,"block_type":"line","text":"* corp 개방(공통 회원머니 적립 issue 조회) — 자기 기업 지급건만.\n* 기업회원머니 지급/회수는 아래 grant API가 담당하며 ORG도 부분트리 범위에서 허용된다.\n* issue 흐름은 서비스관리자/최고관리자 영역이라 ORG는 403.","hangul_chars":70,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* corp는 자기 기업 지급건만 (타기업 mniId 직접 조회 차단)","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":128,"line_end":129,"block_type":"line","text":"* corp 개방 — 서비스에서 자기 기업(scopeAgcId) 소속 회원 외 지급 차단. ORG는 CorpReadonlyGuard가 차단.\n* 조직관리자 기업회원머니 지급/회수는 아래 grant API를 사용한다.","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":196,"line_end":196,"block_type":"line","text":"* dryRun=true: 검증·매칭만, 적용 안 함","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":200,"line_end":202,"block_type":"line","text":"============================================================================\n기업머니 관리\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":281,"line_end":283,"block_type":"line","text":"============================================================================\n기업회원머니 관리\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":360,"line_end":362,"block_type":"line","text":"============================================================================\n내역관리\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":367,"line_end":367,"block_type":"line","text":"* corp 조회 허용(회원머니 내역). 기업머니 풀잔액(th_money_corp)은 별도 corp/:agcId/history 로 제외됨.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":398,"line_end":398,"block_type":"line","text":"* 기업관리자(corp) 스코프 주입 — 자기 기업(agcId) + 조직관리자(ORG)는 org 부분트리(orgPath)만.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":454,"line_end":456,"block_type":"line","text":"============================================================================\n결제관리\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-admin.controller.ts","lang":"js","line_start":515,"line_end":517,"block_type":"line","text":"============================================================================\n환불관리\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-charge-request.entity.ts","lang":"js","line_start":3,"line_end":5,"block_type":"jsdoc","text":"기업머니 충전요청 Entity","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-corp.entity.ts","lang":"js","line_start":3,"line_end":6,"block_type":"jsdoc","text":"기업머니 이력 Entity\n기업의 보유머니 변동 이력","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-corp.entity.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-corp.entity.ts","lang":"js","line_start":58,"line_end":60,"block_type":"jsdoc","text":"기업머니 요약 정보 Entity","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-grant.entity.ts","lang":"js","line_start":3,"line_end":6,"block_type":"jsdoc","text":"기업회원 지급 배치 Entity\n기업머니에서 기업회원에게 \"지급/지급회수\"","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-grant.entity.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-grant.entity.ts","lang":"js","line_start":67,"line_end":69,"block_type":"jsdoc","text":"지급 대상 회원 Entity","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-grant.entity.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-issue.entity.ts","lang":"js","line_start":5,"line_end":8,"block_type":"jsdoc","text":"회원머니 적립 배치 Entity\n관리자가 일반/기업회원에게 머니 \"적립/적립회수\" 일괄 처리","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-issue.entity.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-issue.entity.ts","lang":"js","line_start":104,"line_end":106,"block_type":"jsdoc","text":"적립 대상 회원 Entity","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-issue.entity.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-payment.entity.ts","lang":"js","line_start":3,"line_end":5,"block_type":"jsdoc","text":"결제 정보 Entity","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-payment.entity.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-payment.entity.ts","lang":"js","line_start":76,"line_end":78,"block_type":"jsdoc","text":"결제취소 이력 Entity","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-payment.entity.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-public.controller.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"환경별 프론트엔드 URL 설정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-public.controller.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"환경별 프론트엔드 URL 설정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-refund.entity.ts","lang":"js","line_start":3,"line_end":5,"block_type":"jsdoc","text":"환불 관리 Entity","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-refund.entity.ts","lang":"js","line_start":49,"line_end":49,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-source.entity.ts","lang":"js","line_start":3,"line_end":6,"block_type":"jsdoc","text":"FIFO 원천 Entity\n충전/적립/지급 건별 잔액 추적","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-source.entity.ts","lang":"js","line_start":45,"line_end":48,"block_type":"jsdoc","text":"사용 상세 Entity\nsource 잔액 변동 기록 (FIFO 추적)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-source.entity.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"조인된 데이터 (wallet 정보)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-source.entity.ts","lang":"js","line_start":76,"line_end":79,"block_type":"jsdoc","text":"이용내역 탭 조회용 Entity\nsource → usage → wallet 조인 결과","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-wallet.entity.ts","lang":"js","line_start":3,"line_end":6,"block_type":"jsdoc","text":"유저 머니 이력 Entity\n사용자가 보는 단순 이력 (1건 = 1이력)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-wallet.entity.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"조인된 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-wallet.entity.ts","lang":"js","line_start":49,"line_end":49,"block_type":"line","text":"결제 정보 (충전건)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-wallet.entity.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"grant 정보 (지급/회수 사유)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money-wallet.entity.ts","lang":"js","line_start":68,"line_end":70,"block_type":"jsdoc","text":"머니 이력 요약 정보 Entity","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":44,"line_end":46,"block_type":"line","text":"============================================================================\n머니 조회\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"본인 확인","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"본인 확인","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":87,"line_end":89,"block_type":"line","text":"============================================================================\n머니 충전\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"본인 확인","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":111,"line_end":113,"block_type":"line","text":"============================================================================\n결제 취소\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.controller.ts","lang":"js","line_start":140,"line_end":142,"block_type":"line","text":"============================================================================\n환불 신청\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":116,"line_end":118,"block_type":"line","text":"============================================================================\n관리자 - 회원머니 관리 DTO\n============================================================================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"* 기업 필터 — corp 로그인 시 컨트롤러에서 자기 기업(agcId)으로 강제됨","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":219,"line_end":221,"block_type":"line","text":"============================================================================\n관리자 - 기업머니 관리 DTO\n============================================================================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":287,"line_end":289,"block_type":"line","text":"============================================================================\n관리자/기업관리자 - 기업머니 충전요청 DTO\n============================================================================","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":370,"line_end":372,"block_type":"line","text":"============================================================================\n관리자 - 기업회원머니 관리 DTO\n============================================================================","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":464,"line_end":466,"block_type":"line","text":"============================================================================\n관리자 - 내역관리 DTO\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":492,"line_end":492,"block_type":"line","text":"* 기업관리자 스코프(서버 내부 주입, 클라 미노출) — 자기 기업 회원머니만","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":497,"line_end":497,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":514,"line_end":514,"block_type":"line","text":"회원별 내역 조회 DTO","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":558,"line_end":560,"block_type":"line","text":"============================================================================\n관리자 - 결제관리 DTO\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":610,"line_end":610,"block_type":"line","text":"이용내역 아이템 (프론트엔드 형식)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":633,"line_end":633,"block_type":"line","text":"취소내역 아이템 (프론트엔드 형식)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":652,"line_end":652,"block_type":"line","text":"환불내역 아이템 (프론트엔드 형식)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":687,"line_end":687,"block_type":"line","text":"wallet 정보 (프론트엔드 형식)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":746,"line_end":748,"block_type":"line","text":"============================================================================\n관리자 - 환불관리 DTO\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":808,"line_end":810,"block_type":"line","text":"============================================================================\n유저 - 머니 조회 DTO\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":857,"line_end":859,"block_type":"line","text":"============================================================================\n유저 - 머니 충전 DTO\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":923,"line_end":925,"block_type":"line","text":"============================================================================\n유저 - 결제 취소 DTO\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.dto.ts","lang":"js","line_start":954,"line_end":956,"block_type":"line","text":"============================================================================\n유저 - 환불 신청 DTO\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":56,"line_end":58,"block_type":"line","text":"============================================================================\n회원머니 적립 (tn_money_issue)\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":163,"line_end":164,"block_type":"line","text":"서브쿼리: 회수(EARN_RECOVERY)의 경우 tnMoneySource가 없으므로\nth_money_wallet에서 직접 조회 (mitCreatedAt 기준으로 가장 가까운 이력)","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":188,"line_end":188,"block_type":"line","text":"잔액머니: 적립(source 경유) 또는 회수(서브쿼리)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":195,"line_end":196,"block_type":"line","text":"* 영업대리점: 회원 자체 sag_code 또는 소속기업(agency)의 sag_id로 매칭.\n*   기업회원은 회원 sag_code가 NULL이라 기업 sag로 잡아야 영업대리점이 뜬다(미소속 오표시 방지).","hangul_chars":51,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":209,"line_end":209,"block_type":"line","text":"th_money_wallet 조인: source의 mwlId로 적립 후 전체 잔액 조회","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":243,"line_end":245,"block_type":"line","text":"============================================================================\n기업머니 이력 (th_money_corp)\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":336,"line_end":336,"block_type":"line","text":"현재 잔액은 agency 테이블에서 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":355,"line_end":357,"block_type":"line","text":"============================================================================\n기업머니 충전요청 (tn_money_charge_request)\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":570,"line_end":572,"block_type":"line","text":"============================================================================\n기업회원 지급 (tn_money_grant)\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":672,"line_end":674,"block_type":"jsdoc","text":"결제관리 목록 조회 (searchKey/searchText 패턴)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":679,"line_end":679,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":689,"line_end":689,"block_type":"line","text":"결제상태 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":694,"line_end":694,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":703,"line_end":703,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":709,"line_end":709,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":714,"line_end":714,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":772,"line_end":774,"block_type":"jsdoc","text":"결제관리 카운트 (searchKey/searchText 패턴)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":778,"line_end":778,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":788,"line_end":788,"block_type":"line","text":"결제상태 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":793,"line_end":793,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":802,"line_end":802,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":808,"line_end":808,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":813,"line_end":813,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1008,"line_end":1010,"block_type":"jsdoc","text":"환불관리 목록 조회 (searchKey/searchText 패턴)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1015,"line_end":1015,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1025,"line_end":1025,"block_type":"line","text":"환불상태 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1030,"line_end":1030,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1039,"line_end":1039,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1045,"line_end":1045,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1050,"line_end":1050,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1104,"line_end":1106,"block_type":"jsdoc","text":"환불관리 카운트 (searchKey/searchText 패턴)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1110,"line_end":1110,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1120,"line_end":1120,"block_type":"line","text":"환불상태 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1125,"line_end":1125,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1134,"line_end":1134,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1140,"line_end":1140,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1145,"line_end":1145,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1226,"line_end":1230,"block_type":"jsdoc","text":"특정 결제건(mpyId)과 연관된 환불 내역 조회\nth_money_usage를 통해 해당 결제의 source에서 차감된 환불 내역 조회\nmwlId를 사용하여 정확하게 매칭","hangul_chars":45,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1232,"line_end":1232,"block_type":"line","text":"1. 해당 결제의 source 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1236,"line_end":1236,"block_type":"line","text":"2. 해당 source에서 차감된 usage 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1249,"line_end":1250,"block_type":"line","text":"3. mwlId로 직접 환불 조회 (정확한 매칭)\ntn_money_refund.mwlId는 환불신청 시 생성된 wallet ID","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1265,"line_end":1265,"block_type":"line","text":"4. usage에서 차감 금액 매칭","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1303,"line_end":1305,"block_type":"line","text":"============================================================================\n지갑 이력 (th_money_wallet)\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1354,"line_end":1356,"block_type":"jsdoc","text":"내역관리 목록 조회 (searchKey/searchText 패턴)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1361,"line_end":1361,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1371,"line_end":1371,"block_type":"line","text":"구분 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1376,"line_end":1376,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1385,"line_end":1385,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1391,"line_end":1391,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1396,"line_end":1396,"block_type":"line","text":"* 기업관리자(corp) 스코프 — 자기 기업 회원머니만","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1400,"line_end":1400,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1407,"line_end":1407,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1421,"line_end":1421,"block_type":"line","text":"적립(mniReason) 또는 지급(mngReason) 사유 검색","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1448,"line_end":1448,"block_type":"line","text":"적립(mniReason) 또는 지급(mngReason) 사유 - COALESCE로 둘 중 하나 선택","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1470,"line_end":1472,"block_type":"jsdoc","text":"내역관리 카운트 (searchKey/searchText 패턴)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1476,"line_end":1476,"block_type":"line","text":"날짜 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1486,"line_end":1486,"block_type":"line","text":"구분 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1491,"line_end":1491,"block_type":"line","text":"영업대리점명 조건","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1500,"line_end":1500,"block_type":"line","text":"회원타입 조건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1506,"line_end":1506,"block_type":"line","text":"기업명 조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1511,"line_end":1511,"block_type":"line","text":"* 기업관리자(corp) 스코프 — 자기 기업 회원머니만","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1515,"line_end":1515,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1522,"line_end":1522,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1536,"line_end":1536,"block_type":"line","text":"적립(mniReason) 또는 지급(mngReason) 사유 검색","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1579,"line_end":1579,"block_type":"line","text":"결제 정보 (충전건)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1635,"line_end":1637,"block_type":"jsdoc","text":"wallet 타입 및 설명 업데이트 (환불승인 시 REFUND_REQ → REFUND_OK)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1654,"line_end":1659,"block_type":"jsdoc","text":"FIFO 차감 순서로 source 목록 조회\n1. 유효기간 있는 EARN/GRANT (만료 임박 순)\n2. 유효기간 없는 EARN/GRANT (생성일 순)\n3. CHARGE (생성일 순)","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1669,"line_end":1669,"block_type":"line","text":"1순위: EARN/GRANT 우선 (CHARGE는 나중)","hangul_chars":7,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1671,"line_end":1671,"block_type":"line","text":"2순위: 유효기간 임박 순 (NULL은 맨 뒤)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1673,"line_end":1673,"block_type":"line","text":"3순위: 생성일 순","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1678,"line_end":1680,"block_type":"jsdoc","text":"환불 대상 source 조회 (PURCHASE만, FIFO 순)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1693,"line_end":1695,"block_type":"jsdoc","text":"결제 ID로 source 조회","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1742,"line_end":1745,"block_type":"jsdoc","text":"만료된 source 목록 조회 (스케줄러용)\n- 성능 최적화: EARN/GRANT 타입만 조회 (CHARGE는 유효기간 없음)","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1751,"line_end":1751,"block_type":"line","text":"EARN, GRANT만 조회 (CHARGE는 msrExpiredAt이 NULL이므로 제외)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1759,"line_end":1761,"block_type":"line","text":"============================================================================\n사용 상세 (th_money_usage)\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1775,"line_end":1777,"block_type":"jsdoc","text":"환불신청 wallet의 usage 목록 조회 (복구용)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1785,"line_end":1790,"block_type":"jsdoc","text":"구독 포인트 적립 건 조회 (결제취소 시 회수용)\n- 결제 승인 시간 전후 5분 이내\n- 해당 회원의 EARN 타입\n- \"구독 포인트 적립\" 포함하는 description","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1808,"line_end":1808,"block_type":"line","text":"아직 사용되지 않은 잔액만","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1813,"line_end":1815,"block_type":"jsdoc","text":"결제 이용내역 조회 (source → usage → wallet)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1834,"line_end":1836,"block_type":"line","text":"============================================================================\n회원 관련\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1873,"line_end":1873,"block_type":"line","text":"* 업로드 미리보기 표시용","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1901,"line_end":1905,"block_type":"jsdoc","text":"회원아이디 + 기업코드로 회원 조회.\n - 동일 회원아이디가 여러 기업에 존재할 수 있어, 기업코드(agc_corporate_code, unique)로 해당 기업의 회원만 특정.\n - 회원머니 엑셀업로드에서 오배정(다른 기업 회원에게 적립) 방지용.","hangul_chars":75,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":1914,"line_end":1914,"block_type":"line","text":"* 업로드 미리보기 표시용","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":2057,"line_end":2059,"block_type":"line","text":"============================================================================\n기업 관련\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":2090,"line_end":2092,"block_type":"line","text":"============================================================================\n트랜잭션 지원\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.repository.ts","lang":"js","line_start":2094,"line_end":2096,"block_type":"jsdoc","text":"트랜잭션 실행","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":122,"line_end":124,"block_type":"line","text":"============================================================================\n관리자 - 회원머니 관리\n============================================================================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":126,"line_end":128,"block_type":"jsdoc","text":"회원머니 적립 목록 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"* 기업 필터(corp 로그인 시 컨트롤러가 자기 기업으로 강제)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"searchKey + searchText 패턴 (CODE_STYLE_GUIDE 준수)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":180,"line_end":182,"block_type":"jsdoc","text":"회원머니 적립 상세 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":197,"line_end":199,"block_type":"jsdoc","text":"회원머니 적립/적립회수 일괄 처리","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"* scopeAgcId: 기업관리자(corp) 지급 스코프 — 지정 시 자기 기업으로 강제 + 소속 외 회원 지급 차단","hangul_chars":30,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":206,"line_end":206,"block_type":"line","text":"========== 1단계: 사전 검증 (트랜잭션 외부) ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":212,"line_end":212,"block_type":"line","text":"양수=적립, 음수=회수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"agcId 결정 - 특정회원 선택 시 첫 번째 회원의 소속 기업 사용","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":229,"line_end":229,"block_type":"line","text":"* 기업관리자 지급 스코프: 자기 기업 소속 외 회원 지급/회수 불가 (SPECIFIC 임의 memId 차단)","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":235,"line_end":235,"block_type":"line","text":"agcId 결정 (첫 번째 회원)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":242,"line_end":242,"block_type":"line","text":"적립회수 시 잔액 확인","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":253,"line_end":253,"block_type":"line","text":"검증 실패 시 즉시 에러 반환","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"line","text":"========== 2단계: 트랜잭션으로 일괄 처리 ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"적립 배치 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"각 회원에게 적립/회수 처리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":284,"line_end":284,"block_type":"line","text":"적립 대상 기록","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":296,"line_end":298,"block_type":"jsdoc","text":"대상 회원 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":327,"line_end":329,"block_type":"jsdoc","text":"머니 적립 (EARN)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":348,"line_end":348,"block_type":"line","text":"1. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":357,"line_end":357,"block_type":"line","text":"2. source 생성 (FIFO 추적)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":375,"line_end":375,"block_type":"line","text":"3. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":385,"line_end":389,"block_type":"jsdoc","text":"시스템 적립 (추천인 혜택 등)\n- mniId 없이 적립 가능\n- EARN 타입으로 wallet/source 생성","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":406,"line_end":406,"block_type":"line","text":"1. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":415,"line_end":415,"block_type":"line","text":"2. source 생성 (FIFO 추적)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":427,"line_end":427,"block_type":"line","text":"시스템 적립은 mniId 없음","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":433,"line_end":433,"block_type":"line","text":"3. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":444,"line_end":446,"block_type":"jsdoc","text":"적립 회수 (EARN_RECOVERY)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":469,"line_end":469,"block_type":"line","text":"2. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":488,"line_end":488,"block_type":"line","text":"4. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":498,"line_end":500,"block_type":"line","text":"============================================================================\n관리자 - 기업머니 관리\n============================================================================","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":502,"line_end":504,"block_type":"jsdoc","text":"기업머니 충전/차감 (관리자)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":526,"line_end":526,"block_type":"line","text":"1. 기업머니 이력 생성","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":540,"line_end":540,"block_type":"line","text":"2. agency 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":547,"line_end":549,"block_type":"jsdoc","text":"기업머니 내역 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":585,"line_end":585,"block_type":"line","text":"검색 조건 (SearchDto) - searchKey로 필드 분기","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":601,"line_end":603,"block_type":"line","text":"============================================================================\n기업머니 충전요청\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":808,"line_end":810,"block_type":"line","text":"============================================================================\n관리자 - 기업회원머니 관리 (지급/지급회수)\n============================================================================","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":812,"line_end":814,"block_type":"jsdoc","text":"기업회원 일괄 지급","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":824,"line_end":824,"block_type":"line","text":"========== 1단계: 사전 검증 (트랜잭션 외부) ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":830,"line_end":830,"block_type":"line","text":"대상 회원 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":844,"line_end":844,"block_type":"line","text":"지급: 기업머니가 부족한지 체크","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":851,"line_end":851,"block_type":"line","text":"각 회원별 사전 검증","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":871,"line_end":871,"block_type":"line","text":"회수 시: 회원의 기업머니 잔액 확인","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":886,"line_end":886,"block_type":"line","text":"========== 2단계: 트랜잭션으로 일괄 처리 ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":901,"line_end":901,"block_type":"line","text":"지급 배치 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":918,"line_end":918,"block_type":"line","text":"각 회원에게 지급/회수 처리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":923,"line_end":923,"block_type":"line","text":"회수 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":926,"line_end":926,"block_type":"line","text":"지급 처리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":937,"line_end":938,"block_type":"line","text":"기업머니 변동 이력\n지급: 기업머니 차감 (-), 회수: 기업머니 증가 (+)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":940,"line_end":940,"block_type":"line","text":"회수: 기업으로 돌아옴","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":941,"line_end":941,"block_type":"line","text":"지급: 기업에서 나감","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":971,"line_end":973,"block_type":"jsdoc","text":"기업회원 개별 지급/회수","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1034,"line_end":1034,"block_type":"line","text":"지급 배치 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1072,"line_end":1072,"block_type":"line","text":"기업머니 변동 이력","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1096,"line_end":1098,"block_type":"jsdoc","text":"기업머니 지급 (GRANT)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1118,"line_end":1118,"block_type":"line","text":"1. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1145,"line_end":1145,"block_type":"line","text":"3. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1155,"line_end":1157,"block_type":"jsdoc","text":"지급 회수 (GRANT_RECOVERY)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1179,"line_end":1179,"block_type":"line","text":"1. FIFO 차감 (AGENCY 타입만)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1182,"line_end":1182,"block_type":"line","text":"2. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1201,"line_end":1201,"block_type":"line","text":"4. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1211,"line_end":1213,"block_type":"line","text":"============================================================================\n관리자 - 내역관리\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1215,"line_end":1217,"block_type":"jsdoc","text":"전체 내역 조회 (관리자)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1230,"line_end":1232,"block_type":"jsdoc","text":"머니 내역 엑셀 다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1234,"line_end":1234,"block_type":"line","text":"전체 데이터 조회 (page=0 으로 전체 조회)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1240,"line_end":1240,"block_type":"line","text":"구분 타입 라벨","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1264,"line_end":1264,"block_type":"line","text":"회원타입 라벨","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1309,"line_end":1311,"block_type":"jsdoc","text":"회원별 내역 조회 (관리자)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1321,"line_end":1321,"block_type":"line","text":"필터 조건 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1350,"line_end":1350,"block_type":"line","text":"요약 정보 계산 (전체 데이터 기반)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1394,"line_end":1396,"block_type":"line","text":"============================================================================\n관리자 - 결제관리\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1398,"line_end":1400,"block_type":"jsdoc","text":"결제 목록 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1413,"line_end":1415,"block_type":"jsdoc","text":"결제 목록 엑셀 다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1417,"line_end":1417,"block_type":"line","text":"전체 데이터 조회 (page=0 으로 전체 조회)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1423,"line_end":1423,"block_type":"line","text":"결제상태 라벨","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1437,"line_end":1437,"block_type":"line","text":"회원타입 라벨","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1445,"line_end":1445,"block_type":"line","text":"헤더 설정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1461,"line_end":1461,"block_type":"line","text":"데이터 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1483,"line_end":1483,"block_type":"line","text":"헤더 스타일","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1490,"line_end":1492,"block_type":"jsdoc","text":"결제 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1504,"line_end":1507,"block_type":"jsdoc","text":"결제 이용내역 조회\n프론트엔드 기대 형식: { payment, usageList, cancelList, refundList, wallet, useOnlyAmount }","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1514,"line_end":1514,"block_type":"line","text":"source (wallet) 정보 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1517,"line_end":1518,"block_type":"line","text":"사용 내역 조회 (프론트엔드 형식: usageMthId, mumAmount, mthDescription, mthCreatedAt)\nUSE 타입(머니 사용)만 필터링","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1530,"line_end":1531,"block_type":"line","text":"취소 내역 조회 (프론트엔드 형식: mthId, mthAmount, mthDescription, mthCreatedAt)\nmthAmount: PG 취소 금액 (mpyCanceledAmount) - 관리자용","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1540,"line_end":1540,"block_type":"line","text":"환불 내역 조회 - 해당 결제건(mpyId)과 연결된 환불만 조회","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1544,"line_end":1544,"block_type":"line","text":"이 결제에서 차감된 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1545,"line_end":1545,"block_type":"line","text":"전체 환불 신청 금액","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1553,"line_end":1553,"block_type":"line","text":"wallet 정보 변환 (프론트엔드 형식)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1561,"line_end":1561,"block_type":"line","text":"사용만 한 금액 계산 (환불 제외)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1577,"line_end":1581,"block_type":"jsdoc","text":"관리자 결제 취소\n관리자는 사용된 머니가 있어도 전액 취소 가능\ncancelAmount가 있으면 부분취소, 없으면 전액취소","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1598,"line_end":1598,"block_type":"line","text":"취소 금액 결정 (부분취소 vs 전액취소)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1602,"line_end":1602,"block_type":"line","text":"취소 금액 검증","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1612,"line_end":1612,"block_type":"line","text":"스마트로 PG사 결제 취소 API 호출","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1620,"line_end":1623,"block_type":"line","text":"결제취소 처리\n부분취소 시: cancelAmount만큼 차감\n전액취소 시: 잔액(source.msrRemainingAmount)만큼 차감 (유저 이력)\npgCancelAmount: 실제 PG사에 취소 요청한 금액 (관리자 결제취소금액)","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1635,"line_end":1635,"block_type":"line","text":"PG 취소 금액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1641,"line_end":1643,"block_type":"line","text":"============================================================================\n관리자 - 환불관리\n============================================================================","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1645,"line_end":1647,"block_type":"jsdoc","text":"환불 목록 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1660,"line_end":1662,"block_type":"jsdoc","text":"환불 상세 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1672,"line_end":1674,"block_type":"jsdoc","text":"환불 승인/반려 처리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1694,"line_end":1696,"block_type":"jsdoc","text":"환불 승인","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1698,"line_end":1698,"block_type":"line","text":"1. 환불 상태 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1701,"line_end":1701,"block_type":"line","text":"2. mwlId로 직접 REFUND_REQ wallet 찾아서 REFUND_OK로 업데이트","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1703,"line_end":1703,"block_type":"line","text":"환불신청 → 환불승인으로 타입 및 설명 변경","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1712,"line_end":1714,"block_type":"jsdoc","text":"환불 반려","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1721,"line_end":1721,"block_type":"line","text":"1. mwlId로 직접 usage 조회 후 source remaining 복구","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1739,"line_end":1739,"block_type":"line","text":"2. 환불 상태 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1742,"line_end":1742,"block_type":"line","text":"3. wallet 이력 생성 (REFUND_NO)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1752,"line_end":1752,"block_type":"line","text":"4. REFUND_NO usage 기록 생성 (관리자 이용내역 표시용)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1762,"line_end":1762,"block_type":"line","text":"5. member 잔액 복구","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1771,"line_end":1773,"block_type":"line","text":"============================================================================\n유저 - 머니 조회\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1775,"line_end":1777,"block_type":"jsdoc","text":"내 머니 조회","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1792,"line_end":1794,"block_type":"jsdoc","text":"내 머니 이용내역 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1820,"line_end":1820,"block_type":"line","text":"기간 필터","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1878,"line_end":1880,"block_type":"line","text":"============================================================================\n유저 - 머니 충전 (스마트로 일반결제)\n============================================================================","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1882,"line_end":1884,"block_type":"jsdoc","text":"머니 충전 요청 (스마트로 일반결제 데이터 생성)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1901,"line_end":1903,"block_type":"jsdoc","text":"머니 충전 승인 처리 (스마트로 콜백)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1907,"line_end":1907,"block_type":"line","text":"스마트로 일반결제 승인 API 호출","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1923,"line_end":1923,"block_type":"line","text":"Moid에서 memId 추출 (CHARGE_memId_timestamp 형식)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1934,"line_end":1934,"block_type":"line","text":"1. 결제 정보 저장","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1948,"line_end":1948,"block_type":"line","text":"2. 머니 충전 처리","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1951,"line_end":1951,"block_type":"line","text":"3. 알림톡 발송 (실패해도 결제는 성공 처리)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1981,"line_end":1983,"block_type":"jsdoc","text":"머니 충전 (CHARGE)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":1997,"line_end":1997,"block_type":"line","text":"1. wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2020,"line_end":2020,"block_type":"line","text":"3. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2029,"line_end":2031,"block_type":"line","text":"============================================================================\n유저 - 결제 취소\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2033,"line_end":2035,"block_type":"jsdoc","text":"결제 취소 가능 여부 확인","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2046,"line_end":2046,"block_type":"line","text":"7일 이내 확인","hangul_chars":5,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2063,"line_end":2065,"block_type":"jsdoc","text":"유저 결제 취소","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2087,"line_end":2087,"block_type":"line","text":"스마트로 PG사 결제 취소 API 호출 (유저는 전액취소만 가능)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2107,"line_end":2111,"block_type":"jsdoc","text":"결제 취소 처리 (공통)\n@param amount - 유저 머니에서 차감할 금액 (유저 이력에 표시)\n@param pgCancelAmount - PG사에 취소 요청한 금액 (관리자 결제취소금액에 표시)","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2130,"line_end":2130,"block_type":"line","text":"1. payment 상태 업데이트 (PG 취소 금액 저장)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2134,"line_end":2134,"block_type":"line","text":"2. 취소 이력 저장","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2154,"line_end":2154,"block_type":"line","text":"4. wallet 이력 생성 (CANCEL) - 유저에게는 전액/부분 구분 없이 표시","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2178,"line_end":2178,"block_type":"line","text":"6. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2187,"line_end":2189,"block_type":"line","text":"============================================================================\n유저 - 환불 신청\n============================================================================","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2191,"line_end":2193,"block_type":"jsdoc","text":"환불 가능 정보 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2200,"line_end":2200,"block_type":"line","text":"환불 가능: PURCHASE만 (BASIC, AGENCY는 불가)","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2207,"line_end":2209,"block_type":"jsdoc","text":"환불 신청","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2216,"line_end":2216,"block_type":"line","text":"환불 가능: PURCHASE만 (BASIC, AGENCY는 불가)","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2226,"line_end":2227,"block_type":"line","text":"수수료 계산 (7일 이내 미사용: 0%, 그 외: 5%)\n간소화: 일단 5% 적용","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2231,"line_end":2231,"block_type":"line","text":"1. FIFO 차감 (PURCHASE 우선)","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2236,"line_end":2236,"block_type":"line","text":"2. wallet 이력 생성 (REFUND_REQ)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2245,"line_end":2245,"block_type":"line","text":"3. 환불 신청 생성 (mwlId 포함)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2272,"line_end":2272,"block_type":"line","text":"5. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2283,"line_end":2285,"block_type":"jsdoc","text":"환불 신청 취소","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2300,"line_end":2300,"block_type":"line","text":"환불 삭제 (또는 상태 변경)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2303,"line_end":2304,"block_type":"line","text":"머니 복구 로직은 rejectRefund와 유사\n간소화를 위해 생략 (실제로는 구현 필요)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2309,"line_end":2311,"block_type":"line","text":"============================================================================\nFIFO 차감 로직\n============================================================================","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2313,"line_end":2315,"block_type":"jsdoc","text":"FIFO 순서로 source에서 차감","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2329,"line_end":2329,"block_type":"line","text":"특정 머니 타입만 차감하는 경우","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2353,"line_end":2355,"block_type":"jsdoc","text":"환불을 위한 FIFO 차감 (PURCHASE만)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2378,"line_end":2378,"block_type":"line","text":"PURCHASE가 부족하면 에러 (AGENCY는 환불 불가)","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2386,"line_end":2388,"block_type":"line","text":"============================================================================\n머니 사용 (청구서 발급 등)\n============================================================================","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2390,"line_end":2392,"block_type":"jsdoc","text":"머니 사용 (외부에서 호출)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2409,"line_end":2409,"block_type":"line","text":"wallet 이력 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2428,"line_end":2429,"block_type":"line","text":"member 잔액 계산 및 업데이트\nusage에서 각 타입별 차감 금액 계산","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2454,"line_end":2462,"block_type":"jsdoc","text":"머니 사용 취소 (부분 환불 지원)\n- useMoney로 차감된 내역을 원래 타입(BASIC/PURCHASE/AGENCY)별로 정확히 복원\n- 부분 환불: mwlId의 usage 중 restoreAmount만큼만 FIFO 역순으로 복원\n\n@param mwlId - useMoney 시 생성된 wallet ID\n@param restoreAmount - 복원할 금액 (전액이면 원래 차감액과 동일)\n@param description - 유저에게 보이는 설명 (예: \"팩스 발송 실패 환불\")","hangul_chars":84,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2464,"line_end":2464,"block_type":"line","text":"1. 원본 wallet 조회","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2475,"line_end":2475,"block_type":"line","text":"2. usage 조회 (어떤 source에서 얼마 차감됐는지)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2481,"line_end":2481,"block_type":"line","text":"3. 부분 환불: FIFO 역순(마지막에 차감된 것부터)으로 restoreAmount만큼 복원","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2485,"line_end":2485,"block_type":"line","text":"usage를 역순으로 처리 (마지막 차감분부터 복원)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2505,"line_end":2505,"block_type":"line","text":"source 잔액 복원","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2509,"line_end":2509,"block_type":"line","text":"타입별 복원 금액 집계","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2519,"line_end":2519,"block_type":"line","text":"5. 복원 wallet 이력 생성 (유저에게 보이는 1건)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2529,"line_end":2529,"block_type":"line","text":"6. 복원 usage 기록 (관리자가 source별 상세를 볼 수 있도록)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2539,"line_end":2539,"block_type":"line","text":"7. member 잔액 복원 (타입별 정확히)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2550,"line_end":2552,"block_type":"line","text":"============================================================================\n스케줄러 - 머니 소멸\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2554,"line_end":2556,"block_type":"jsdoc","text":"만료된 머니 소멸 처리 (스케줄러에서 호출)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2569,"line_end":2569,"block_type":"line","text":"1. source remaining 0으로 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2572,"line_end":2572,"block_type":"line","text":"2. wallet 이력 생성 (EXPIRE)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2589,"line_end":2589,"block_type":"line","text":"4. member 잔액 업데이트","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2615,"line_end":2617,"block_type":"line","text":"============================================================================\n구독 포인트 회수 (결제취소 시)\n============================================================================","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2619,"line_end":2624,"block_type":"jsdoc","text":"구독 포인트 적립 회수 (결제취소 시 호출)\n@param memId 회원 ID\n@param approvedAt 결제 승인 시간\n@param pmtTid 결제 TID (로그용)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2626,"line_end":2626,"block_type":"line","text":"1. 해당 결제 시점에 적립된 구독 포인트 조회","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2640,"line_end":2640,"block_type":"line","text":"2. 회원 정보 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2648,"line_end":2648,"block_type":"line","text":"3. source 잔액 0으로 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2651,"line_end":2651,"block_type":"line","text":"4. wallet 이력 생성 (EARN_RECOVERY)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2668,"line_end":2668,"block_type":"line","text":"6. member 잔액 업데이트 (기본 머니에서 차감)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2679,"line_end":2681,"block_type":"line","text":"============================================================================\n관리자 - 회원머니 엑셀 양식 다운로드/업로드\n============================================================================","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2683,"line_end":2685,"block_type":"jsdoc","text":"회원머니 적립 엑셀 양식 다운로드","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2692,"line_end":2694,"block_type":"jsdoc","text":"회원머니 적립 엑셀 양식 샘플 데이터","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2736,"line_end":2738,"block_type":"jsdoc","text":"회원머니 적립 엑셀 양식 컬럼","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2743,"line_end":2743,"block_type":"line","text":"* 동일 회원아이디가 여러 기업에 있어 기업회원은 기업코드로 특정(미입력 시 적립 거부). 일반회원은 비워둠.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2752,"line_end":2754,"block_type":"jsdoc","text":"회원머니 적립 엑셀 업로드","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2762,"line_end":2762,"block_type":"line","text":"첫 번째 시트 사용 (시트명 검증 제거)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2769,"line_end":2770,"block_type":"line","text":"* ★ 양식 검증 — 옛 양식(기업코드 컬럼 없는 6열)으로 업로드하면 3열부터 한 칸씩 밀려\n*   금액이 엉뚱한 열에서 읽혀 잘못된 금액/회원에 적용될 수 있다(금전사고). 헤더로 강제 차단.","hangul_chars":67,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2772,"line_end":2773,"block_type":"line","text":"* ExcelJS .text = 표시 텍스트(리치텍스트/스타일 무관). Excel에서 저장한 파일은 헤더가\n*   리치텍스트 객체로 바뀌어 .value.toString()이 \"[object Object]\"가 되므로 .text를 쓴다.","hangul_chars":45,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2796,"line_end":2796,"block_type":"line","text":"헤더 스킵","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2798,"line_end":2799,"block_type":"line","text":"* 컬럼: ①구분 ②회원아이디 ③기업코드(기업회원 필수) ④금액 ⑤내용 ⑥사유 ⑦유효기간\n*   Excel 저장 파일의 리치텍스트 대응 위해 문자열은 .text로 읽는다.","hangul_chars":51,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2873,"line_end":2873,"block_type":"line","text":"========== 1단계: 사전 검증 (트랜잭션 외부) ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2877,"line_end":2877,"block_type":"line","text":"적립회수(음수)인데 유효기간이 설정된 경우","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2883,"line_end":2885,"block_type":"line","text":"회원 존재 확인\n* 기업회원은 동일 회원아이디가 여러 기업에 존재 → 기업코드로 특정(미입력 시 거부, 오배정 방지).\n*   일반회원은 기업개념이 없어 회원아이디로 조회.","hangul_chars":64,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2913,"line_end":2913,"block_type":"line","text":"적립회수 시 잔액 확인","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2940,"line_end":2940,"block_type":"line","text":"검증 실패 시 즉시 에러 반환","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2945,"line_end":2947,"block_type":"line","text":"* ★ 미리보기(dryRun): 검증·회원매칭까지만 하고 적용은 안 한다.\n*   화면에서 \"이 명단/금액 맞나요?\" 모달로 사람이 확인 후 실제 업로드(dryRun=false)하게 해 오적용을 막는다.\n*   적용과 100% 동일한 파싱·검증 경로를 타므로 미리보기 통과 = 적용 성공이 보장된다.","hangul_chars":88,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":2980,"line_end":2980,"block_type":"line","text":"========== 2단계: 트랜잭션으로 일괄 처리 ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3044,"line_end":3046,"block_type":"line","text":"============================================================================\n기업회원머니 엑셀 양식 다운로드/업로드\n============================================================================","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3048,"line_end":3050,"block_type":"jsdoc","text":"기업회원머니 지급 엑셀 양식 다운로드","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3120,"line_end":3122,"block_type":"jsdoc","text":"기업회원머니 지급 엑셀 양식 샘플 데이터","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3142,"line_end":3144,"block_type":"jsdoc","text":"기업회원머니 지급 엑셀 양식 컬럼","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3155,"line_end":3157,"block_type":"jsdoc","text":"기업회원머니 지급 엑셀 업로드","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3175,"line_end":3175,"block_type":"line","text":"기업 정보 확인","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3184,"line_end":3184,"block_type":"line","text":"첫 번째 시트 사용 (시트명 검증 제거)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3204,"line_end":3204,"block_type":"line","text":"헤더 스킵","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3249,"line_end":3250,"block_type":"line","text":"========== 1단계: 사전 검증 (트랜잭션 외부) ==========\n지급 총액 계산 (양수만)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3256,"line_end":3256,"block_type":"line","text":"기업머니 잔액 확인 (지급 총액)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3263,"line_end":3263,"block_type":"line","text":"각 행별 검증","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3278,"line_end":3278,"block_type":"line","text":"해당 기업 소속 회원인지 확인","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3299,"line_end":3299,"block_type":"line","text":"회수(음수) 시: 회원의 기업머니 잔액 확인","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3311,"line_end":3311,"block_type":"line","text":"========== 2단계: 트랜잭션으로 일괄 처리 ==========","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3414,"line_end":3416,"block_type":"line","text":"============================================================================\n스마트로 PG 결제 취소\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/money/money.service.ts","lang":"js","line_start":3418,"line_end":3420,"block_type":"jsdoc","text":"스마트로 일반결제 취소 API 호출","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 분석만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 고객 인적사항 마스킹은 영업대리점만 — corp 마스킹은 기획 요청(7/31)으로 일단 제거","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 분석만","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":138,"line_end":139,"block_type":"line","text":"* 기업/조직관리자 노출여부 변경 허용(2026-07 기획 — 분석관리 공통 화면).\n*  대상 분석이 전부 자기 기업 소속(조직관리자는 자기 부분트리 소속)인지 검증 후 처리.","hangul_chars":59,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail-admin.controller.ts","lang":"js","line_start":182,"line_end":192,"block_type":"line","text":"! 필요시 수정필요\n@ApiOperation({\n  summary: `분석목록 삭제처리`,\n  description: `분석목록에서 복수의 분석목록을 삭제처리를 합니다.`,\n})\n@Post('deletion')\nasync updateDeletionOrderDetail(\n  @Body() body: UpdateAdminArrayOrderDetailDto,\n) {\n  return await this.orderDetailService.updateArrayOrderDetail(body);\n}","hangul_chars":37,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.controller.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 조회 대상은 토큰으로만 정한다. 클라가 보낸 memId를 믿으면 숫자만 바꿔 남의 목록이 조회된다.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.controller.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* 조회 대상은 토큰으로만 정한다(클라 전송 memId 무시).","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.dto.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.dto.ts","lang":"js","line_start":96,"line_end":97,"block_type":"line","text":"* 사용자 조직필터 경로(서버 내부 주입, 클라 노출 안 함) — orgId → org_path LIKE prefix.\n*   JWT 스코프(orgPath)와 별개 AND 결합(교집합).","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.dto.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"* 1차 인증 라우팅된 공급자 (멀티 디스패처). 생성 시점부터 박아 인증실패도 업체 귀속되게.","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.dto.ts","lang":"js","line_start":397,"line_end":397,"block_type":"line","text":"* 소속조직(기업조직) — 목록 '소속조직' 컬럼용. 소속 없으면 null.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.module.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 기업조직: 조직필터/소속조직 전체 경로 병합에 사용.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":67,"line_end":67,"block_type":"jsdoc","text":"신규 주문상세 처리 및 알림톡의 사용여부 사용으로 처리 추가","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":84,"line_end":88,"block_type":"line","text":"* corp 노출여부 변경 스코프 검증 — ids 중 해당 기업(agcId) 소속 분석 건수.\n*  기업 소속 판정은 목록(buildDynamicQuery)과 동일하게 구독 체인(주문→결제→구독→회원) 기준.\n*  (고객 tn_user가 회원과 연결되지 않은 분석 건도 목록과 동일하게 인정하기 위함 —\n*   tnUser.memId 기준으로 세면 고객 미연결 건이 0으로 떨어져 403이 난다)\n*  orgPath가 주어지면(조직관리자) 회원 소속 org가 해당 부분트리 하위인 것만 센다(목록 스코프와 동일 규칙).","hangul_chars":138,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":179,"line_end":179,"block_type":"line","text":"* 재분석 가드용: 수집된 진료 원본(tt_treat_basic)이 있는지. 없으면 재분석=빈완료(가짜)라 호출부에서 차단.","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":189,"line_end":193,"block_type":"jsdoc","text":"재분석 준비: final_state 클리어 + 차감 옵션에 따라 settled 마커 / 예약수 조정.\n- charge=true : settled 0 reset + ord_reserved +1 (정상 사이클 재시작)\n- charge=false: settled 1 유지 (분석완료/실패 시 카운터 영향 X), final_state 만 클리어","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":196,"line_end":197,"block_type":"line","text":"* 차감 재분석: 일반 분석요청(reserveQty)과 동일하게 한도 검증 후 예약수 +1.\n 사용완료+예약 < 한도 조건부 UPDATE → affected=0 이면 한도초과로 차단(트랜잭션 롤백).","hangul_chars":50,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":218,"line_end":219,"block_type":"line","text":"* 기존 분석 결과 row 삭제 (createAnalyze 가 INSERT 시 PK 중복 충돌 회피)\n FK 의존성 순서: detail → basic. 자료(tt_treat_*) 는 그대로 유지.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":237,"line_end":238,"block_type":"line","text":"* odd_state 를 자료분석중(ODD005) 으로 즉시 set\n 화면에서 진행상태 표시 + 활성 조건(ODD002/ODD007) 어긋나서 중복 클릭 차단.","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":259,"line_end":261,"block_type":"jsdoc","text":"분석목록 생성일시가 현시간보다 5분이상 초과되었고\n분석상태가 [인증요청중] (ODD001)인 경우","hangul_chars":35,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":288,"line_end":290,"block_type":"jsdoc","text":"자료수집완료(ODD002) / 자료분석중(ODD005) 인데 1시간 경과 + 최종분석상태 미박힘\n → 스케줄러가 final_state=분석실패(ODD007) 박고 환불","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":314,"line_end":314,"block_type":"jsdoc","text":"생성일이 한달이 경과된 목록","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":361,"line_end":365,"block_type":"jsdoc","text":"엑셀 전체다운로드용 keyset 배치 조회.\n - oddId DESC 고정 정렬 + oddId < lastOddId 로 다음 배치 → OFFSET 없이 일정 속도(대량 export).\n - 전체를 한 번에 받지 않고 배치로 흘려 스트리밍 → 응답 즉시 시작(게이트웨이 타임아웃 회피)·메모리 일정.","hangul_chars":71,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":378,"line_end":378,"block_type":"line","text":"* withFailReason=false: 행당 서브쿼리 2개 생략 → 실패사유는 getFailReasonsByTxIds로 배치 합침(속도↑).","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":387,"line_end":391,"block_type":"jsdoc","text":"엑셀 export용: 배치 거래번호들의 '마지막 진짜 실패(CRT002)' 코드/메시지를 한 번에 조회.\n - 행당 상관 서브쿼리(2회) 대신 배치당 IN쿼리 1회 → 대량 export 속도 대폭 개선.\n - 거래당 최신 1건만(ROW_NUMBER). 자동차/CAR-NODATA/CF-QUEUE 제외(서브쿼리와 동일 기준).","hangul_chars":75,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":429,"line_end":429,"block_type":"line","text":"* false면 실패사유 상관 서브쿼리(행당 2회)를 생략 → 엑셀 배치 export에서 IN쿼리로 한 번에 합친다.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":442,"line_end":442,"block_type":"line","text":"* 소속조직 — 목록 '소속조직' 컬럼용(orgFullPath는 서비스에서 배치 병합).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":469,"line_end":469,"block_type":"line","text":"* 수집 타임아웃 실패 — 목록에서 재시도 대신 건강이음 안내","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":472,"line_end":472,"block_type":"line","text":"* raw 상태값 — 엑셀 export(withFailReason=false) 시 Node에서 자동실패(ODD004/ODD007) 폴백 사유 재현용. 목록/엑셀 컬럼엔 미노출.","hangul_chars":29,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":475,"line_end":477,"block_type":"line","text":"* 실패사유 — 해당 거래의 마지막 '진짜' 실패(CRT002) log_treat 코드/메시지. 성공행은 NULL. idx_odd_tx 사용.\n*   자동차(CAT002/CAR-NODATA, 미수집은 정상)·대기열(CF-QUEUE)은 실패 아니므로 제외.\n*   목록=행당 서브쿼리. 엑셀 대량 export=서브쿼리 생략(NULL) 후 getFailReasonsByTxIds로 배치 합침.","hangul_chars":72,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":483,"line_end":483,"block_type":"line","text":"* 실패사유: log_treat 실패행 우선. 없고 백업 자동처리(final=ODD004 인증실패 / ODD007 분석실패)면 raw odd_state로 단계 구분 사유.","hangul_chars":33,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":554,"line_end":554,"block_type":"jsdoc","text":"가망고객용 whereClause - bod_assigned_member_id로 조회 (B2C)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":558,"line_end":558,"block_type":"line","text":"memId로 로그인 ID 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":570,"line_end":570,"block_type":"line","text":"담당자 ID로 필터링","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":573,"line_end":573,"block_type":"line","text":"검색어가 있으면 B2C 검색","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":582,"line_end":582,"block_type":"jsdoc","text":"가망고객 목록 조회 (B2C)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":648,"line_end":648,"block_type":"jsdoc","text":"가망고객 카운트 (B2C)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":659,"line_end":659,"block_type":"jsdoc","text":"B2C 검색 조건","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":700,"line_end":700,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":707,"line_end":707,"block_type":"line","text":"* 사용자 조직필터(orgId→경로) — JWT 스코프(orgPath)와 AND 교집합.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":719,"line_end":719,"block_type":"line","text":"* 유저/관리자 공통필수","hangul_chars":9,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":723,"line_end":723,"block_type":"line","text":"* 노출여부 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":739,"line_end":739,"block_type":"line","text":"* 처리업체(공급자) 필터","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":764,"line_end":764,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.repository.ts","lang":"js","line_start":875,"line_end":875,"block_type":"jsdoc","text":"가망고객용 orderByClause (B2C)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* 기업조직: 조직필터(orgId→경로) 변환 + 소속조직 전체 경로(orgFullPath) 병합용.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"* 사용자 조직필터: orgId → org_path prefix(orgFilterPath) 변환(해당 조직+하위 포함).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":59,"line_end":59,"block_type":"jsdoc","text":"분석 목록조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 소속조직 전체 경로 병합 — distinct orgId 배치 조회 후 row에 orgFullPath 부여.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":87,"line_end":87,"block_type":"jsdoc","text":"가망고객 목록조회 (담당자로 지정된 B2C 고객)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":104,"line_end":104,"block_type":"jsdoc","text":"FC 목록 엑셀다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":113,"line_end":114,"block_type":"line","text":"* 전체다운로드: 10만+ 행을 한 번에 받으면 쿼리만 분 단위라 게이트웨이 타임아웃에 끊긴다.\n*   keyset(oddId<lastId) 배치로 끊어 받아 엑셀 스트림에 즉시 흘려보낸다 → 응답이 바로 시작돼 타임아웃 회피·메모리 일정.","hangul_chars":74,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"* 고객 인적사항 마스킹은 영업대리점만 — corp 마스킹은 기획 요청(7/31)으로 일단 제거","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"* 소속조직 전체 경로 캐시 — 배치 간 동일 orgId 중복 조회 방지.","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 실패사유: 행당 서브쿼리 대신 배치 거래번호를 한 번에 조회해 합친다(속도↑).","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":143,"line_end":143,"block_type":"line","text":"* '소속조직' 컬럼용 orgFullPath — 배치 내 미조회 orgId만 모아 getFullPathNames 1회 배치 조회.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":160,"line_end":160,"block_type":"line","text":"* 소속조직 전체 경로 부여(소속 없으면 null).","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"* 실패사유 병합 + 자동실패(ODD004 인증실패 / ODD007 분석실패) 폴백 재현(쿼리 COALESCE와 동일 기준).","hangul_chars":29,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"* 영업대리점·기업/조직관리자는 개인정보 마스킹","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":221,"line_end":221,"block_type":"line","text":"* corp 노출여부 변경 스코프 검증 — ids 중 해당 기업(조직관리자는 자기 부분트리) 소속 분석 건수","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"* 주문상세 추가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":240,"line_end":240,"block_type":"line","text":"* 주문상세 상태변경","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":247,"line_end":247,"block_type":"line","text":"* 관리자 강제종결: 최종분석상태 박기 + 예약수 환불 (atomic, 중복 호출 시 no-op)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":260,"line_end":264,"block_type":"line","text":"* 관리자 재분석:\n - 활성화 조건은 controller 단에서 검증 (분석상태가 자료수집완료/분석실패)\n - chargeQuantity=true : settled 0 reset + ord_reserved +1 → 정상 사이클로 분석완료시 사용수+1\n - chargeQuantity=false: settled 1 유지 → addQuantity 마커 가드로 카운터 영향 X\n - 분석 실행은 'treatCompare' 이벤트로 비동기","hangul_chars":70,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":270,"line_end":271,"block_type":"line","text":"* 재분석 가드: 수집 데이터 없으면 reset(상태→자료분석중·예약+1) 선반영 전에 차단.\n*   안 막으면 가드가 compare에서 막아도 자료분석중+예약1 중간상태가 남는다(가짜완료는 어차피 차단됨).","hangul_chars":67,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 분석만 비동기 실행. 결과는 관리자 알람으로 push.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":291,"line_end":292,"block_type":"line","text":"* 유저 재시도용: 재분석 준비(기존 분석결과 삭제 + 차감 시 잔여량 검증/예약)만 동기 수행.\n 관리자 reAnalyze 와 달리 이벤트/알람 없이 호출측(treatService)에서 바로 분석 이어감.","hangul_chars":59,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":297,"line_end":297,"block_type":"line","text":"* 스케줄러 테스트용 (스케줄러 동작 확인후 삭제할 것)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":309,"line_end":309,"block_type":"line","text":"* 주문상세(분석) 상태값 변경 및 FC알림추가","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":314,"line_end":314,"block_type":"line","text":"* 요청전 검증 로직(분석완료 혹은 자료분석중일 경우 요청 무시)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":326,"line_end":326,"block_type":"line","text":"almMessage: '진료정보분석인증이 실패되었어요.',","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":341,"line_end":342,"block_type":"line","text":"* 종결 상태(ODD004 인증실패 / ODD007 분석실패 / ODD008 자료수집실패) 박을 때 예약수 환불\n ord 단위 환불은 odd_reservation_settled 마커로 1회 보장","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":357,"line_end":357,"block_type":"line","text":"* 주문상세(분석) 노출/비노출, 삭제 배열처리","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":362,"line_end":362,"block_type":"line","text":"* 해당 구독권의 주문상세 비노출 일괄처리","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":380,"line_end":380,"block_type":"line","text":"* 주문상세 상태값 변경이 필요한 목록 상태값 업데이트","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":385,"line_end":385,"block_type":"line","text":"* 1시간 지나도 자료수집완료/자료분석중인 분석 stall 목록","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":390,"line_end":393,"block_type":"line","text":"* stall 분석 일괄 final_state=분석실패(ODD007) 처리 + 환불\n*   인증은 통과했고 수집/분석 단계에서 멈춘 건이므로 분석실패(ODD007)로 분류한다.\n*   (자료수집완료/자료분석중 stall → 분석실패. 직전 인증실패 통일 변경은 합의와 어긋나 환원.)\n*   raw odd_state(ODD002/005)는 보존 → 관리자 화면에서 '자료수집 미완료' 사유로 구분.","hangul_chars":98,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":410,"line_end":411,"block_type":"line","text":"* 5분 경과 인증요청중/추가인증요청중 일괄 final_state=인증실패 처리 + 환불\n raw odd_state 는 보존 (관리자 화면에서 원본 진행상태 식별 가능하도록).","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":424,"line_end":427,"block_type":"line","text":"* 임시데이터 삭제가 필요한 목록\nasync getDeleteOrderDetailForSchedule() {\n  return await this.orderDetailRepository.getDeleteListForSchedule();\n}","hangul_chars":13,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":430,"line_end":430,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order-detail/order-detail.service.ts","lang":"js","line_start":432,"line_end":433,"block_type":"line","text":"* 기획(2026-07, company-mockup): 기업/조직관리자는 영업대리점명·영업채널명·회원타입·\n*  처리업체·실패코드·실패사유·분석실패일 제외 — 화면 목록 컬럼 구성과 동일 순서","hangul_chars":57,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 주문만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":87,"line_end":90,"block_type":"line","text":"@Header(\n  'Content-Disposition',\n  `attachment;filename*=utf-8''${encodeURIComponent('주문목록')}.xlsx`,\n)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 주문만","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order-admin.controller.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"타입에 따른 명칭 설정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.controller.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"* 조회 대상은 토큰으로만 정한다. 클라가 보낸 memId를 믿으면 숫자만 바꿔 남의 주문이 조회된다.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":86,"line_end":87,"block_type":"line","text":"* 사용자 조직필터 경로(서버 내부 주입, 클라 노출 안 함) — orgId → org_path LIKE prefix.\n*   JWT 스코프(orgPath)와 별개 AND 결합(교집합).","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"* 과금방식 필터(기업주문관리) — 주문 스냅샷(ord_billing_type) 기준","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":101,"line_end":101,"block_type":"line","text":"* 정산상태 필터(기업주문관리) — 목록 컬럼과 동일 산출식","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":426,"line_end":426,"block_type":"line","text":"* 소속조직(기업조직) — 목록 '소속조직' 컬럼용. 소속 없으면 null.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":448,"line_end":450,"block_type":"line","text":"* 정산상태(기업주문관리 목록) — 주문의 최신 정산 기준 산출값.\n*   PENDING=정산대기(이월·미확정·미편입) | CONFIRMED=정산확정 | EXCLUDED=정산제외(확정+미반영)\n*   | FREE=무상제공(과금방식 스냅샷) | NONE=공란(주문취소·실패 — 정산 무관)","hangul_chars":72,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.dto.ts","lang":"js","line_start":461,"line_end":461,"block_type":"line","text":"* 과금방식 스냅샷(주문 생성 시점 계약 기준) — 기업FC 주문만 값 보유, B2C는 null","hangul_chars":26,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":55,"line_end":61,"block_type":"jsdoc","text":"@param dto : CreateTransactionOrderPaymentDto\n@param unsubscribed : 구독상태 해지처리여부\n@param scheduled : 스케줄러동작여부\n@returns","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":82,"line_end":83,"block_type":"line","text":"* 결제실패시 unsubscribed의 값에 따라 구독상태 변경하기\n* subNextPayDay : 스케줄러이고, 구독해지가 아닐 경우 당일로 변경","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":103,"line_end":104,"block_type":"line","text":"* 결제완료/스케줄러 동작일 경우 다음 정기결제일 업데이트(구독중/변경건 구분없음)\n* 결제완료/즉시결제 및 신규구독일 경우엔 정기결제일 변경없음","hangul_chars":60,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":137,"line_end":137,"block_type":"line","text":"결제정보 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":144,"line_end":146,"block_type":"line","text":"* 과금방식 스냅샷(기획 §3.4) — 주문 생성 시점의 활성계약 act_billing_type 복사.\n*   계약이 나중에 바뀌어도 과거 주문의 정산 집계·표시 기준은 생성 시점 방식 유지.\n*   매칭 계약 없으면 POSTPAID(기존 정책과 동일).","hangul_chars":68,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"주문정보 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":173,"line_end":174,"block_type":"line","text":"* 주문이 '정산확정(CONFIRMED) 정산에 반영(INCLUDE)'돼 있는지 — 주문취소 차단 가드용.\n*   이월 주문은 map 행이 복수라 EXISTS 로 어느 정산이든 확정+반영이면 true.","hangul_chars":48,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":219,"line_end":222,"block_type":"jsdoc","text":"분석완료: 예약 → 완료 전환 (총 점유 유지).\nsettled 마커 set 성공한 경우에만 카운터 이동. 중복 호출 시 no-op.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":249,"line_end":249,"block_type":"jsdoc","text":"인증요청중 진입: 예약수 +1을 조건부 atomic 수행. 한도 초과면 affectedRows=0","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":267,"line_end":270,"block_type":"jsdoc","text":"certify CODEF 실패 환불: odd 생성 전이라 마커가 없음. 단순 ord -1.\n호출 흐름상 reserveQty 직후 1회만 발생.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":280,"line_end":285,"block_type":"jsdoc","text":"예약수 정합성 보정: ord_reserved_qty 를 실제 진행중 order_detail 개수로 재계산.\n진행중 = 비종료 상태(ODD001/002/003/005) AND 최종분석상태 미박힘(final_state IS NULL).\n  ※ stale 인증실패는 raw state 가 ODD001 로 남고 final_state 만 박히므로 final_state 필터 필수.\n+1/-1 환불 누락으로 카운터가 새도 주기 실행으로 자가치유. 불일치 주문만 갱신.","hangul_chars":85,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":297,"line_end":301,"block_type":"jsdoc","text":"인증실패/분석실패/관리자 강제종결: 예약수 환불.\nodd 단위 settled 마커를 atomic 0→1 로 set 한 경우에만 ord 카운터 차감.\n중복 호출 / 이미 환불된 odd 는 no-op.","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":327,"line_end":330,"block_type":"jsdoc","text":"관리자 강제종결: odd_final_state 박기 + 예약수 환불 묶음.\n이미 final_state 박혀있거나 settled 된 odd 는 affected=0 반환.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":341,"line_end":342,"block_type":"line","text":"* 자동실패(인증/분석 미완료)도 실패시각을 남긴다 → 모니터 처리량·실패 집계가\n*   odd_failed_at 기준이라, 미기록 시 탈주건이 통째로 누락된다.","hangul_chars":50,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":367,"line_end":370,"block_type":"jsdoc","text":"SMS 제출과 인증 만료 정리가 같은 주문상세를 동시에 처리하지 못하도록\n수집 시작을 DB 행에서 원자적으로 선점한다.","hangul_chars":45,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":394,"line_end":397,"block_type":"jsdoc","text":"인증 대기 상태인 경우에만 만료+환불을 선점한다.\n수집 선점(ODD005)이 먼저 끝났다면 affected=0이라 취소하지 않는다.","hangul_chars":40,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":439,"line_end":439,"block_type":"line","text":"* 기업 접근차단(불량) — 초대링크 접근 유효성 검사용","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":445,"line_end":445,"block_type":"line","text":"* 탈퇴(일반)/계정중지(기업) — 초대링크 접근 유효성 검사용","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":451,"line_end":451,"block_type":"line","text":"* 구독 이용종료일 — 초대링크 접근 유효성 검사용","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":689,"line_end":689,"block_type":"line","text":"* 소속조직 — 목록 '소속조직' 컬럼용(orgFullPath는 서비스에서 배치 병합).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":692,"line_end":692,"block_type":"line","text":"* 정산상태(기업주문관리) — 주문의 최신 정산(ast_id 최대) 기준. settleStateCase() 참조.","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":694,"line_end":694,"block_type":"line","text":"* 과금방식 스냅샷 — 선불(PREPAID)/후불(POSTPAID)/무상(FREE). B2C 주문은 NULL.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":771,"line_end":772,"block_type":"line","text":"* 정렬키(ordCreatedAt)가 동일한 행이 많으면(월정기 일괄생성 등) LIMIT/OFFSET 순서가\n*   비결정적이라 페이지 이동 시 같은 데이터가 반복 노출됨 → ordId 타이브레이커로 고정.","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":801,"line_end":801,"block_type":"line","text":"TODO 추후 agency.settlement.repository.ts로 리팩토링 필요","hangul_chars":9,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":822,"line_end":825,"block_type":"line","text":"* 정산상태 산출(기업주문관리) — 목록 컬럼과 검색필터가 같은 식을 공유.\n*   PENDING 정산대기(이월·미확정·미편입) | CONFIRMED 정산확정 | EXCLUDED 정산제외(확정+미반영)\n*   | FREE 무상제공(과금방식 스냅샷) | NONE 공란(주문취소·실패 — 정산 무관)\n*   이월 주문은 map 행이 2개(원 정산 CARRYOVER + 익월 INCLUDE)라 최신(ast_id 최대) 1건만 본다.","hangul_chars":98,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":866,"line_end":866,"block_type":"line","text":"* 과금방식 필터(기업주문관리) — 주문 스냅샷 기준","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":871,"line_end":871,"block_type":"line","text":"* 정산상태 필터(기업주문관리) — 목록 컬럼과 동일 산출식으로 비교","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":891,"line_end":891,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":898,"line_end":898,"block_type":"line","text":"* 사용자 조직필터(orgId→경로) — JWT 스코프(orgPath)와 AND 교집합.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":925,"line_end":925,"block_type":"line","text":"* 상품타입","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":939,"line_end":939,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.repository.ts","lang":"js","line_start":1010,"line_end":1010,"block_type":"line","text":"* 프론트 옵션 값이 'member.memLoginId'처럼 프리픽스로 오는 경우 마지막 키로 정규화.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"* 기업조직: 조직필터(orgId→경로) 변환 + 소속조직 전체 경로(orgFullPath) 병합용.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 사용자 조직필터: orgId → org_path prefix(orgFilterPath) 변환(해당 조직+하위 포함).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* 소속조직 전체 경로 병합 — distinct orgId 배치 조회 후 row에 orgFullPath 부여.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"jsdoc","text":"주문 목록","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":111,"line_end":111,"block_type":"jsdoc","text":"주문 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"* 다운로드 행에도 '소속조직' 컬럼용 orgFullPath 병합(전체 배열 반환 경로).","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":132,"line_end":132,"block_type":"line","text":"* 기업주문 엑셀 라벨 필드 — 과금방식/정산상태/정산금액(확정 시만) 한글 표기 주입.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":198,"line_end":198,"block_type":"jsdoc","text":"분석완료: 예약 → 완료 전환 (odd 단위 idempotent)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":207,"line_end":207,"block_type":"jsdoc","text":"인증요청중 진입: 예약수 +1. 한도 초과면 ORDER_NOT_AVAILABLE throw","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":220,"line_end":220,"block_type":"jsdoc","text":"certify CODEF 실패: odd 없음. 단순 ord -1","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":229,"line_end":229,"block_type":"jsdoc","text":"예약수 정합성 보정: 실제 진행중(비종료 AND final 미박힘) 개수로 재계산. 보정된 주문 수 반환","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":237,"line_end":237,"block_type":"jsdoc","text":"인증실패/분석실패: 예약수 -1 환불 (odd 단위 idempotent)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":246,"line_end":246,"block_type":"jsdoc","text":"관리자 강제종결: 최종분석상태 박기 + 예약수 환불 (한 번만)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"* order 생성(신규구독/정기구독)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":276,"line_end":281,"block_type":"jsdoc","text":"@param dto : CreateOrderDto\n@param unsubscribed : 결제실패후 해지처리여부\n@returns","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":283,"line_end":283,"block_type":"line","text":"* 주문번호 생성","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":285,"line_end":285,"block_type":"line","text":"* 분기처리 필요","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":310,"line_end":310,"block_type":"line","text":"* 결제실패시에만 적용","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":328,"line_end":328,"block_type":"line","text":"결제 성공 시 처리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":330,"line_end":330,"block_type":"line","text":"구독 포인트 적립","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":340,"line_end":340,"block_type":"line","text":"유효기간 없음","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":346,"line_end":346,"block_type":"line","text":"포인트 지급 실패해도 주문은 정상 처리","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":349,"line_end":349,"block_type":"line","text":"정기주문인 경우 알림톡 발송","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":372,"line_end":372,"block_type":"line","text":"알림톡 발송 실패해도 주문은 정상 처리","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":417,"line_end":417,"block_type":"line","text":"TODO 유효성검사 필요시 추가","hangul_chars":10,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":430,"line_end":436,"block_type":"jsdoc","text":"@param dto\n결제후 7일이내 인지\n해지한 건이 아닌지\n분석이력을 한 건이라도 사용했는지","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":451,"line_end":451,"block_type":"line","text":"* 관리자 / 유저 분기처리","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":456,"line_end":457,"block_type":"line","text":"* 정산확정된(확정+반영) 주문은 취소 불가 — 확정금액 스냅샷 훼손 방지.\n*   취소하려면 정산관리에서 정산확정 해제 후 진행.","hangul_chars":47,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":523,"line_end":523,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":564,"line_end":565,"block_type":"line","text":"* 기업관리자 콘솔(2026-07, company-mockup): 목록 화면 컬럼 구성·순서와 동일 —\n*  영업대리점명·분석사용완료수·분석진행수·과금방식·정산상태·정산금액 제외","hangul_chars":52,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/order/order/order.service.ts","lang":"js","line_start":599,"line_end":599,"block_type":"line","text":"* 기업주문관리(admin) — 목록 화면 컬럼 순서와 동일하게 유지(과금방식/정산상태/정산금액 포함)","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.repository.ts","lang":"js","line_start":11,"line_end":11,"block_type":"line","text":"* TID로 결제 정보 조회 (memId, pmtApprovedAt 포함)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.repository.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 결제취소시 구독해지까지 자동처리","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"빌링키로 결제 요청하기","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 카드가 있는 경우 빌링키 찾고, 대표카드로 설정하기","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"* 구독상품","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"line","text":"결제 취소 시 지급된 적립금 회수","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"대리점은 실제 결제 취소 없이 DB만 업데이트","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"대리점도 지급된 적립금 회수","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":182,"line_end":185,"block_type":"jsdoc","text":"구독 결제 취소 시 지급된 적립금 회수\n- 해당 결제에서 지급된 구독 포인트가 있으면 회수 처리","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":188,"line_end":188,"block_type":"line","text":"해당 결제의 subId로 구독 정보 조회 → memId 획득","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":194,"line_end":194,"block_type":"line","text":"회원 ID와 결제 승인 시간 확인","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":203,"line_end":203,"block_type":"line","text":"MoneyService를 통해 구독 포인트 회수","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/payment/payment.service.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"적립금 회수 실패해도 결제 취소는 진행","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/popup/popup-admin.controller.ts","lang":"js","line_start":140,"line_end":140,"block_type":"line","text":"* editor 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/popup/popup.service.ts","lang":"js","line_start":98,"line_end":98,"block_type":"jsdoc","text":"상품 신규등록 이미지 데이터","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/popup/popup.service.ts","lang":"js","line_start":124,"line_end":124,"block_type":"jsdoc","text":"s3 이미지 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/product/product.dto.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"* 상품 선택 옵션에 분석건수/금액 병기(기업계약 화면 요청)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/product/product.repository.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"* 상품 선택 옵션에 분석건수/금액 병기(기업계약 화면 요청)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/product/product.repository.ts","lang":"js","line_start":221,"line_end":221,"block_type":"line","text":"* 상품타입","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.spec.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* \"abc,xyz\"처럼 유효 agcId가 0개여도 전체발송이 된다 — 위험 동작을 명시적으로 고정.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":1,"line_end":7,"block_type":"jsdoc","text":"푸시 발송 대상(누가 받는가) 결정 — 순수 로직.\n\n분리 이유: 기업회원 푸시에서 \"선택 기업(agcId)\" 누락 시 조용히 전체발송되던 사고(push 13, 1.3만명)가 있었다.\n - \"누가 받는가\"는 안전 임계 로직이라 DB/스키마와 분리해 단위테스트로 회귀를 막는다.\n - 특히 \"기업회원인데 agcId가 비면 = 전체 기업회원\"이라는 위험한 기본동작을 명시적으로 검증한다.","hangul_chars":123,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"푸시 대상구분 코드 (push.dto PushTargetType과 동일 문자열)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"필터할 회원타입. null = 타입 무관(전 회원).","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":20,"line_end":23,"block_type":"jsdoc","text":"기업회원(MEM002) 중 특정 기업 agcId 목록.\nnull = 해당 타입 전체(= 전체 기업회원). ⚠️ 이게 비어 NULL이면 전체발송이 된다.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":27,"line_end":27,"block_type":"jsdoc","text":"\"34,30,36\" → [34,30,36]. 공백/빈값/숫자아님은 제거.","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":36,"line_end":41,"block_type":"jsdoc","text":"대상구분 + 선택기업ID 문자열 → 발송 대상 해석.\n - fc / mem001  → 일반회원(MEM001) 전체\n - agency / mem002 → 기업회원(MEM002). agcId 있으면 그 기업만, 없으면 전체 기업회원\n - all          → 전 회원","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push-target.util.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"all (또는 미지정) → 조건 없음","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.dto.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 다중 인스턴스 동시 실행 방어용 중간상태. pending → sending 으로 1대만 선점 후 발송.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.dto.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"대문자 버전 (프론트엔드 호환)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.scheduler.ts","lang":"js","line_start":11,"line_end":14,"block_type":"jsdoc","text":"매시 정각마다 예약된 푸시 발송\n한국시간 기준 09:00, 10:00, 11:00 등 매시간마다 실행","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"빈 문자열을 null로 처리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"푸시 알림 저장만 하고 발송하지 않음","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"* 기업회원 발송 시 특정 기업(agcId) 목록을 저장. 특정회원(targetUserIds)은 폴백.","hangul_chars":23,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 기업회원 발송 시 특정 기업(agcId) 목록을 저장. 특정회원(targetUserIds)은 폴백.","hangul_chars":23,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"1. 푸시 정보 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"재발송 허용 (상태 체크 제거)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"2. 대상 회원 조회 (FCM 토큰 필터링 없이)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"3. FCM 발송 및 알람 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"line","text":"알람 생성 (이벤트 푸시) - 모든 회원에게 생성 (설정 무관)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"FCM 푸시 발송 (FCM 토큰이 있고 + 이벤트/혜택 알림 동의한 회원만)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"동작 타입 결정: pshUrl이 있으면 'link', 없으면 'detail'","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":145,"line_end":145,"block_type":"line","text":"4. 발송 완료 상태 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":172,"line_end":172,"block_type":"line","text":"5. 발송 실패 상태 업데이트","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":193,"line_end":193,"block_type":"line","text":"* \"누가 받는가\" 결정은 순수 유틸로 분리(단위테스트로 회귀 방지). agcIds null = 해당 타입 전체.","hangul_chars":31,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":199,"line_end":199,"block_type":"line","text":"memType null(ALL)이면 조건 없음","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":239,"line_end":242,"block_type":"jsdoc","text":"스케줄러용: 예약된 푸시 발송\n현재 시간 이하의 예약시간을 가진 대기중인 푸시를 모두 발송","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":246,"line_end":246,"block_type":"line","text":"현재 시간 이하의 예약 시간을 가진 대기중인 푸시 조회","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":265,"line_end":265,"block_type":"line","text":"각 푸시 발송","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":268,"line_end":271,"block_type":"line","text":"* 다중 인스턴스 동시 실행 방어: pending → sending 원자적 선점.\n api 서비스는 여러 인스턴스로 떠 있고 각 인스턴스가 이 스케줄러를 매시 정각에 실행한다.\n 위 SELECT 는 여러 인스턴스가 동시에 같은 pending 푸시를 집어갈 수 있으므로,\n 발송 직전 조건부 UPDATE 로 1대만 선점(affectedRows=1)하게 하여 중복 발송을 차단한다.","hangul_chars":102,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":297,"line_end":297,"block_type":"line","text":"searchKey 또는 searchField로 검색 필드 결정 (프론트엔드 SearchForm은 searchKey를 사용)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":300,"line_end":300,"block_type":"line","text":"searchField에 따라 제목 또는 내용 검색","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":304,"line_end":304,"block_type":"line","text":"기본값은 제목 검색","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"예약 타입 필터 (immediate: 즉시발송, scheduled: 예약발송)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":334,"line_end":334,"block_type":"line","text":"동작방식 필터 (link: URL 있음, detail: URL 없음)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":362,"line_end":362,"block_type":"line","text":"pshScheduledType 계산: pshScheduledAt이 있으면 scheduled, 없으면 immediate","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":366,"line_end":366,"block_type":"line","text":"동작방식: pshUrl이 있으면 링크, 없으면 상세","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":386,"line_end":390,"block_type":"jsdoc","text":"푸시 발송 내역 조회 (tn_alarm 기록 기반)\n- 발송 시 almType='SND004', almRedirectId=pshId 로 회원별 알람이 쌓임\n- 회원타입/기업명/열람여부 필터 + 회원아이디 검색 + 페이지네이션","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":448,"line_end":448,"block_type":"line","text":"1. 해당 푸시와 연결된 알람 삭제","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":453,"line_end":453,"block_type":"line","text":"2. 푸시 삭제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":471,"line_end":471,"block_type":"line","text":"1. 해당 푸시와 연결된 알람 삭제 (사용자가 보지 못하도록)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/push/push.service.ts","lang":"js","line_start":478,"line_end":478,"block_type":"line","text":"2. 푸시 상태를 CANCELLED로 변경 (취소 표시)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":19,"line_end":21,"block_type":"jsdoc","text":"추천인 혜택 설정 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":31,"line_end":33,"block_type":"jsdoc","text":"추천인 혜택 설정 수정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"기존 데이터 확인","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"업데이트","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"신규 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":67,"line_end":69,"block_type":"jsdoc","text":"추천인 회원 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"WHERE 조건 생성","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"날짜 검색","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"키워드 검색","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"피추천인 조회 (referee: 추천코드를 사용한 사람)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.repository.ts","lang":"js","line_start":136,"line_end":138,"block_type":"jsdoc","text":"추천인 회원 총 개수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.service.ts","lang":"js","line_start":9,"line_end":11,"block_type":"jsdoc","text":"추천인 혜택 설정 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.service.ts","lang":"js","line_start":16,"line_end":18,"block_type":"jsdoc","text":"추천인 혜택 설정 수정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/referral/referral.service.ts","lang":"js","line_start":23,"line_end":25,"block_type":"jsdoc","text":"추천인 회원 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund-admin.controller.ts","lang":"js","line_start":1,"line_end":5,"block_type":"line","text":"@ApiTags('[관리자] 주문환불')\n@UseGuards(AdminJwtAuthGuard)\n@Controller('admin/refund')\nexport class AdminRefundController {\n  constructor(private refundService: RefundService) {}","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund-admin.controller.ts","lang":"js","line_start":7,"line_end":17,"block_type":"line","text":"@Post()\n  @ApiOperation({\n    summary: `환불 신규등록\n              환불완료처리시 환불완료일 백엔드에서 해당 시간으로 자동저장 됨\n              프론트에서 환불완료일을 지정하여 저장해야 할 경우 수정필요함\n              ** 환불완료처리 시 구독상태 [해지]로 업데이트트`,\n  })\n  async createRefund(@Body() body: CreateRefundDto) {\n    await this.refundService.createRefund(body);\n    return;\n  }","hangul_chars":80,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund-admin.controller.ts","lang":"js","line_start":19,"line_end":32,"block_type":"line","text":"//* (구독상태를 구독으로 변경 시에 정기결제일과 동일한 날에 처리된 경우 스케줄러 이슈가 있을 수 있음)\n  @Post('edit/:refId')\n  @ApiOperation({\n    summary: '환불 수정',\n    description: `환불반려 -> 환불완료시 구독상태[해지]로 업데이트\n                  환불완료 -> 환불반려시 구독상태[해지] 상태로 유지`,\n  })\n  async updateRefund(\n    @Param('refId') refId: number,\n    @Body() body: UpdateRefundDto,\n  ) {\n    await this.refundService.updateRefund(refId, body);\n    return;\n  }","hangul_chars":85,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund-admin.controller.ts","lang":"js","line_start":34,"line_end":43,"block_type":"line","text":"@Post('delete')\n  @ApiOperation({\n    summary: '환불 삭제',\n    description: `환불완료처리한 주문 건에 대해서는 삭제불가`,\n  })\n  async deleteRefund(@Body() body: DeleteRefundDto) {\n    await this.refundService.deleteRefund(body);\n    return;\n  }\n}","hangul_chars":23,"class":"1_policy","tags":["1_policy","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund.entity.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"환불완료","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/refund/refund.entity.ts","lang":"js","line_start":8,"line_end":8,"block_type":"line","text":"환불반려","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/channel/sales-agency-channel-admin.controller.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* 영업대리점(관리자)가 접근시 검증후 검색조건에 영업대리점 포함","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/channel/sales-agency-channel-admin.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"* 해당 채널 코드를 통해 가입한 유저가 있을시","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/channel/sales-agency-channel.repository.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"* 회원 sacCode 기반 카운트","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 해당 영업대리점을 통해 가입한 기업이 있을 시","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"영업대리점별 일별, 월별, 전체 - 가입자 | 결제금액 | 결제취소금액 통계","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"* 반복문을 통해 발송 form 세팅","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":199,"line_end":199,"block_type":"line","text":"* 세팅된 form p-limit을 통해 5개씩 병렬 비동기(promise) 처리","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":208,"line_end":208,"block_type":"line","text":"* 실패건 확인","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 실패건이 한개 이상일시 실패 로그 적재","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"* 에러 형태별 처라","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":231,"line_end":231,"block_type":"line","text":"예상치 못한 형태의 reason","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency-admin.service.ts","lang":"js","line_start":239,"line_end":239,"block_type":"line","text":"* 에러 내용 log 테이블에 적재 (일간보고 발송건은 항상 sagId 지정 — MailerSendDto의 sagId 선택화에 따른 방어)","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"* 총판 영업대리점 코드만 조회","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":181,"line_end":181,"block_type":"jsdoc","text":"영업대리점 목록 이메일 발송 Y인 대리점만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":326,"line_end":326,"block_type":"line","text":"* 영업대리점 일반회원 카운트","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":356,"line_end":356,"block_type":"line","text":"* 영업대리점 기업회원 카운트","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":380,"line_end":380,"block_type":"line","text":"* 영업대리점 기준 일반회원 결제금액","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.repository.ts","lang":"js","line_start":501,"line_end":501,"block_type":"line","text":"* 영업대리점 기준 기업회원 결제금액","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/sales-agency/sales-agency.service.ts","lang":"js","line_start":8,"line_end":8,"block_type":"line","text":"* 총판대리점 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.repository.ts","lang":"js","line_start":53,"line_end":56,"block_type":"jsdoc","text":"질병코드가 있을 경우 update\n질병코드가 없을 경우 insert","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.repository.ts","lang":"js","line_start":193,"line_end":209,"block_type":"line","text":"* 번복가능성이 있기 때문에 우선 주석처리\nconst inclusionData = await this.drizzle\n  .select({\n    sdsCode: tcSearchDisease.sdsCode,\n    sdsName: tcSearchDisease.sdsName,\n    sdsContent: tcSearchDisease.sdsContent,\n  })\n  .from(tcSearchDisease)\n  .where(\n    and(\n      like(tcSearchDisease.sdsCode, `%${searchText}%`),\n      not(eq(tcSearchDisease.sdsCode, searchText)),\n    ),\n  )\n  .orderBy(asc(tcSearchDisease.sdsCode))\n  .limit(limit)\n  .offset(offset);","hangul_chars":17,"class":"2_rationale","tags":["2_rationale","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":48,"line_end":48,"block_type":"jsdoc","text":"목록 엑셀다운로드","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"jsdoc","text":"양식 다운로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":80,"line_end":80,"block_type":"jsdoc","text":"질병코드검색데이터 업로드","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":110,"line_end":110,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":120,"line_end":120,"block_type":"jsdoc","text":"양식 컬럼","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":129,"line_end":131,"block_type":"jsdoc","text":"엑셀 데이터 추출\nReadable.from(buffer)로 읽어올 시 한글 깨짐현상 발생","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":174,"line_end":174,"block_type":"jsdoc","text":"업로드 데이터 유효성 검사","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":214,"line_end":214,"block_type":"jsdoc","text":"데이터 업로드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/search/search.service.ts","lang":"js","line_start":225,"line_end":225,"block_type":"jsdoc","text":"엑셀 업로드 인터페이스","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.controller.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 영업대리점 관리자 일 경우","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.repository.ts","lang":"js","line_start":153,"line_end":153,"block_type":"line","text":"* 영업대리점 관리자를 위한 통계 작업 start(추후에 가능하다면 Refactoring 필요)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.repository.ts","lang":"js","line_start":405,"line_end":405,"block_type":"line","text":"* 영업대리점 관리자를 위한 통계 작업 end","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.repository.ts","lang":"js","line_start":415,"line_end":415,"block_type":"line","text":"전월/전일 대비 계산을 위하여 전월/전일 날짜 계산","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.repository.ts","lang":"js","line_start":607,"line_end":607,"block_type":"line","text":"TODO 추구 수정 필수!!","hangul_chars":6,"class":"1_policy","tags":["1_policy","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.repository.ts","lang":"js","line_start":618,"line_end":618,"block_type":"line","text":"TODO 추후 수정 필수!!","hangul_chars":6,"class":"1_policy","tags":["1_policy","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"전체회원수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"월신규회원수","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"전체분석완료건수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"월분석완료건수","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"전체 결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"월별 결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"일별결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* 영업대리점 통계","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"전체회원수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"월신규회원수","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"전체분석완료건수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"월분석완료건수","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"전체 결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"월별 결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"일별결제/결제취소 금액","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"* 가입통계 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":185,"line_end":185,"block_type":"line","text":"기간 내 가입통계 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":193,"line_end":193,"block_type":"line","text":"기간 내 가입/탈퇴 결과","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":201,"line_end":201,"block_type":"line","text":"전월/전일 비율 계산","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":209,"line_end":209,"block_type":"line","text":"* 매출통계 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":217,"line_end":217,"block_type":"line","text":"기간 내 매출 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":225,"line_end":225,"block_type":"line","text":"기간 내 매출결과","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"* 분석통계 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":242,"line_end":242,"block_type":"line","text":"* 기간 내 분석결과 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":249,"line_end":249,"block_type":"line","text":"* 분석결과별 통계","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"* 분석완료/분석실패","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":264,"line_end":264,"block_type":"line","text":"* 인증실패/분석실패/기타","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 기간 내 분석결과 상세","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":286,"line_end":286,"block_type":"line","text":"상세리스트 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":296,"line_end":296,"block_type":"line","text":"//* 챗봇 통계 조회","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":298,"line_end":298,"block_type":"line","text":"TODO: 가입통계/매출통계 작업 완료 시 코드 수정 및 리팩토링 진행","hangul_chars":24,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":308,"line_end":308,"block_type":"line","text":"월별/일별 데이터 불러오기","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":322,"line_end":322,"block_type":"line","text":"* 가입통계","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":366,"line_end":366,"block_type":"line","text":"* 매출통계","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":377,"line_end":377,"block_type":"line","text":"* 분석통계","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":609,"line_end":609,"block_type":"line","text":"날짜 포멧팅","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":620,"line_end":620,"block_type":"line","text":"비율계산","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":625,"line_end":625,"block_type":"line","text":"전체 월 범위 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":640,"line_end":640,"block_type":"line","text":"전체 일 범위 생성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":655,"line_end":655,"block_type":"line","text":"분석결과별 통계","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":681,"line_end":681,"block_type":"line","text":"가입통계 상세 리스트 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":691,"line_end":691,"block_type":"line","text":"dates 배열의 첫 번째 날짜의 이전 달/일 계산","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":719,"line_end":719,"block_type":"line","text":"매출결과 상세 리스트 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":749,"line_end":749,"block_type":"line","text":"분석결과 상세 리스트 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":785,"line_end":785,"block_type":"line","text":"전월/전일 비율 계산","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":802,"line_end":802,"block_type":"line","text":"* 월별/일별 통계 비율 산정","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":807,"line_end":807,"block_type":"line","text":"* 가입자 통계 데이터 구분(전월, 전일, 당월, 당일)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":815,"line_end":815,"block_type":"line","text":"* 전월, 월, 전일, 일 구분","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":839,"line_end":839,"block_type":"line","text":"* 일별 결제/결제취소 리스트 생성","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/statistics/statistics.service.ts","lang":"js","line_start":867,"line_end":867,"block_type":"line","text":"* 구글 챗 rich card 형태로 포맷팅","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.repository.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"* 상품타입","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.repository.ts","lang":"js","line_start":265,"line_end":265,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"* 재구독(스케줄러) — 동시 실행 수를 추적. subId 3만 실패 처리.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"* 순차: 동시 실행 최대 1건 (계약행 데드락 방지의 핵심)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 4건 모두 재구독 시도","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 성공(1,2,4)만 삭제, 실패(3)는 삭제 안 함","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"* 순서 유지 + 중간 실패가 나머지를 막지 않음(allSettled 시맨틱 보존)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"구독 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":57,"line_end":57,"block_type":"jsdoc","text":"재구독 처리","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* 순차 처리 — 같은 기업 계약행 동시 업데이트 데드락 방지(구독 실패 재구독 일괄). settleInBatches(BATCH_SIZE=1).","hangul_chars":31,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"실패한 구독 정보 추출","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"에러 출력","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":105,"line_end":105,"block_type":"line","text":"실패한 구독 ID 목록","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.ts","lang":"js","line_start":120,"line_end":120,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 구독만 조회","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":73,"line_end":76,"block_type":"line","text":"@Header(\n  'Content-Disposition',\n  `attachment;filename*=utf-8''${encodeURIComponent('구독목록')}.xlsx`,\n)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":83,"line_end":83,"block_type":"line","text":"타입에 따른 명칭 설정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":90,"line_end":90,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe-admin.controller.ts","lang":"js","line_start":95,"line_end":95,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업 구독만","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.dto.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.dto.ts","lang":"js","line_start":85,"line_end":86,"block_type":"line","text":"* 사용자 조직필터 경로(서버 내부 주입, 클라 노출 안 함) — orgId → org_path LIKE prefix.\n*   JWT 스코프(orgPath)와 별개 AND 결합(교집합).","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.dto.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 구독즉시변경","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.dto.ts","lang":"js","line_start":397,"line_end":397,"block_type":"line","text":"* 소속조직(기업조직) — 목록 '소속조직' 컬럼용. 소속 없으면 null.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.module.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 기업조직: 조직필터/소속조직 전체 경로 병합에 사용.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"* 정기구독시 변경예정상품 upsert","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":253,"line_end":253,"block_type":"line","text":"* 임시테이블 삭제","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 타입이 예약이고, 구독상태가 변경일 경우 (예약변경)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":287,"line_end":288,"block_type":"line","text":"* 타입이 예약이고, 구독상태가 구독일 경우 (예약변경취소)\n* 타입이 해지이고, 구독상태가 해지일 경우 (구독해지)","hangul_chars":44,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":327,"line_end":331,"block_type":"jsdoc","text":"해지처리 대상자\n스케줄러 매일 자정이므로 sub_next_pay_day가 해당일의 전날기준으로\n구독상태가 [해지]이고 마지막 order의 ord_expired_at가 만료된 것들 가져오기","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":382,"line_end":382,"block_type":"line","text":"* 소속조직 — 목록 '소속조직' 컬럼용(orgFullPath는 서비스에서 배치 병합).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":441,"line_end":442,"block_type":"line","text":"* 정렬키(subCreatedAt 등)가 동일한 행이 많으면(엑셀 일괄생성 등) LIMIT/OFFSET 순서가\n*   비결정적이라 페이지 이동 시 같은 데이터가 반복 노출됨 → subId 타이브레이커로 고정.","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":473,"line_end":478,"block_type":"jsdoc","text":"@param scheduled : 스케줄러 여부\n@param id : subId (즉시결제일경우)\n@returns","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":495,"line_end":495,"block_type":"line","text":"* 구독상태가 변경이라면 변경되는 상품으로 가져오기","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":585,"line_end":589,"block_type":"jsdoc","text":"해지처리 대상자\n스케줄러 매일 자정이므로 sub_next_pay_day가 해당일의 전날기준으로\n구독상태가 [해지]이고 마지막 order의 ord_expired_at가 만료된 것들 가져오기","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":609,"line_end":609,"block_type":"line","text":"* 구독 다음 결제일 수정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":628,"line_end":628,"block_type":"line","text":"* 구독 다음 예정일 먼저 변경","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":667,"line_end":667,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":674,"line_end":674,"block_type":"line","text":"* 사용자 조직필터(orgId→경로) — JWT 스코프(orgPath)와 AND 교집합.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":681,"line_end":681,"block_type":"line","text":"//* 상품타입","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":718,"line_end":718,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.repository.ts","lang":"js","line_start":774,"line_end":774,"block_type":"line","text":"* 프론트 옵션 값이 'member.memLoginId'처럼 프리픽스로 오는 경우 마지막 키로 정규화.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 기업조직: 조직필터(orgId→경로) 변환 + 소속조직 전체 경로(orgFullPath) 병합용.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 사용자 조직필터: orgId → org_path prefix(orgFilterPath) 변환(해당 조직+하위 포함).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 소속조직 전체 경로 병합 — distinct orgId 배치 조회 후 row에 orgFullPath 부여.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":113,"line_end":113,"block_type":"jsdoc","text":"구독 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 다운로드 행에도 '소속조직' 컬럼용 orgFullPath 병합(전체 배열 반환 경로).","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":135,"line_end":135,"block_type":"jsdoc","text":"무료체험구독하기(신규가입자 전용)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":137,"line_end":137,"block_type":"line","text":"* 체험상품찾기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":139,"line_end":139,"block_type":"line","text":"* 체험상품 구독하기","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":143,"line_end":149,"block_type":"jsdoc","text":"신규구독, 즉시구독변경\n@param dto : CreateSubscriptionDto\n@param trialled : 무료체험구독 여부 (최초가입자전용용)\n@param prompted : 즉시구독변경 여부\n@returns","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":155,"line_end":155,"block_type":"line","text":"*무료체험구독이 아니고 즉시구독변경이 아닌 경우, 최신 구독현황의 유효성검사","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":206,"line_end":206,"block_type":"line","text":"* 결제실패시","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":216,"line_end":216,"block_type":"line","text":"* 기업 신규구독","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":363,"line_end":363,"block_type":"line","text":"* 구독정보","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":383,"line_end":383,"block_type":"line","text":"* 유저의 최신구독정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":388,"line_end":388,"block_type":"line","text":"* 병명예측 기능 권한 체크","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":390,"line_end":390,"block_type":"line","text":"DEV_USER (memId: 180) 또는 화이트리스트 IP용 개발 계정은 구독 체크 건너뛰기","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":404,"line_end":404,"block_type":"line","text":"구독 상태 및 유효기간 확인","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":417,"line_end":417,"block_type":"line","text":"모든 구독상품에 병명예측이 포함됨으로 별도 권한 체크 불필요","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":421,"line_end":421,"block_type":"line","text":"* 구독해지","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":441,"line_end":441,"block_type":"line","text":"* 예약변경","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":457,"line_end":461,"block_type":"jsdoc","text":"@param dto : PromptSubscribeDto\n즉시변경 : 기존구독해지 -> 변경구독가입","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":472,"line_end":472,"block_type":"line","text":"* 결제완료시 이전 구독상품 해지처리","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":496,"line_end":497,"block_type":"line","text":"*------------------------ Schedule ------------------------*//\n! 해지예약완료스케줄러 확인 후 삭제처리하기","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":498,"line_end":498,"block_type":"jsdoc","text":"구독해지처리(=해지완료일) 목록","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":511,"line_end":511,"block_type":"jsdoc","text":"해지예약 해지완료일 추가처리 해지완료 알람필요없음","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":516,"line_end":519,"block_type":"jsdoc","text":"정기구독정보목록\n1.Subscribe subNextPayDay의 결제일이 해당일인 경우\n2.product type이 구독상품인 경우","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":524,"line_end":527,"block_type":"jsdoc","text":"기업정기구독정보목록\n1.Subscribe subNextPayDay의 결제일이 해당일인 경우\n2.product type이 기업상품인 경우","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":532,"line_end":540,"block_type":"jsdoc","text":"정기구독 주문결제요청\n1. 스케줄러를 통한 주문결제요청\n2. 정기결제일 당일의 즉시결제\n- 구독해지->구독해지취소일 경우\n- 첫번째 결제시도시 결제실패났을 경우 카드 변경후 즉시결제하는 경우\n- 또는 그 외?\nunsubscribed : 결제실패시의 해지처리여부\nprompted : 즉시결제여부 (true:즉시결제 |false:스케줄러)","hangul_chars":107,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":597,"line_end":602,"block_type":"jsdoc","text":"결제실패 시\n1)즉시결제일 경우엔 throw\n2)즉시결제가 아니고 unsubscribed가 해지(true)일경우 결제성공/실패와 상관없이 알림만\n3)즉시결제가 아니고 unsubscribed가 구독유지(false)일경우\n  결제성공/실패와 상관없이 알림 + 실패일 경우알림톡","hangul_chars":78,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":609,"line_end":609,"block_type":"line","text":"* 즉시결제X | 해지처리O 일시 : 알람","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":621,"line_end":621,"block_type":"line","text":"* 즉시결제x | 구독상태변경x 일시 : 알람 + 알림톡","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":640,"line_end":640,"block_type":"line","text":"* 기업 정기구독","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":646,"line_end":646,"block_type":"line","text":"계약이 해지된 경우 => 구독해지 후 로직 종료","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":655,"line_end":655,"block_type":"line","text":"계약 상품이 변경된 경우 => 기존 구독해지 + 신규구독","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":718,"line_end":718,"block_type":"line","text":"계약 상품이 유지된 경우 => 결제 및 주문정보만 생성","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":859,"line_end":864,"block_type":"jsdoc","text":"@param dto\n결제상태가 결제완료이며 구독 혹은 변경예정인 상품이 있는 경우\n해지를 했지만 이용기간이 남아있는 경우","hangul_chars":44,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":866,"line_end":866,"block_type":"line","text":"order가 없으면 검증 스킵","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":887,"line_end":887,"block_type":"line","text":"* 구독 다음 결제일 수정 처리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":892,"line_end":892,"block_type":"line","text":"* 다음 결제일이 빈값일 경우","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/subscribe/subscribe/subscribe.service.ts","lang":"js","line_start":905,"line_end":905,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/config/profiles.ts","lang":"js","line_start":3,"line_end":5,"block_type":"line","text":"* 테스터 전용 자격증명은 실서비스 env와 분리: TEST_DEV_* / TEST_PROD_* 사용.\n* UI select(dev/prod)가 어댑터로 전달한 env에 따라 접두사를 골라 읽는다.\n* 실서비스 env(CODEF_ID 등)는 건드리지 않음.","hangul_chars":51,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/config/profiles.ts","lang":"js","line_start":16,"line_end":16,"block_type":"jsdoc","text":"모듈 부트 시 1회 주입 (TreatTestService 생성자에서 호출)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/config/profiles.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* env(=UI select) → TEST_DEV_* / TEST_PROD_* 접두사. 미지정 시 dev.","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":1,"line_end":9,"block_type":"jsdoc","text":"유저 단계 → 벤더별 API 단계 → 각 API 단계의 오류/정상 응답 (흐름/Flow 뷰용).\n\n두 가지 단계 개념을 분리:\n - 개념단계(SCENARIO_META.stage): 유저가 그 실수를 하는 단계(중앙 유저단계 태그용). INPUT_INVALID=REQUEST(유저1) 등.\n - 표출단계(VENDOR_FLOWS step.scenarios): 그 native코드가 실제로 드러나는 벤더 API 단계.\n   ⚠️ codef는 1차 certify가 입력검증 없이 CF-03002(성공)만 반환 → 입력오류 포함 모든 오류가 2차(treat)에서 표출.\n      coocon은 본인인증(1차)에서 즉시 검증 → 1차에서 표출. (벤더마다 다름)","hangul_chars":132,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"canonical 오류 시나리오. stage=개념단계(유저단계 태그용), category, authOnly","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":41,"line_end":44,"block_type":"jsdoc","text":"벤더별 인증 대기/세션 만료 시간 (문서·코드 근거). 미기재는 테스트로 측정.\n'인증 시간 초과(미응답)' = authWait, '2차 세션 만료 후' = session 에 대응.","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* 공통: 우리 HTTP treat 요청 timeout 300s · 멀티 디스패처 슬롯 TTL 600s(실측 OTP승인+수집 ~3.4분)","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":71,"line_end":71,"block_type":"jsdoc","text":"이 단계의 정상/진행 응답 코드 (오류 아님)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/flows.ts","lang":"js","line_start":73,"line_end":73,"block_type":"jsdoc","text":"이 단계에서 표출되는 오류 시나리오: 명시 배열 | 'ALL'(전 오류, 로그아웃 제외) | 'NONE'(정상만)","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":1,"line_end":5,"block_type":"jsdoc","text":"진료내역 오류 매핑 현황 기준 데이터 (정적).\n출처: insuniverse-server 코드 분석 + docs/진료내역_오류규격_마스터시트.xlsx\n/mapping-status 에서 라이브 catalog(테스트로 관측된 코드)와 합쳐 진척도를 보여준다.","hangul_chars":61,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"통합 택소노미: category(SNAKE_CASE) → 유저 노출 메시지 (단일 출처)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":30,"line_end":33,"block_type":"jsdoc","text":"노출 대상(audience): 'user'=유저에게 구체 메시지 노출 / 'ops'=유저엔 generic, 상세는 로그·DB·관리자(추적/분석)만.\n⚠️ audience 무관하게 모든 에러는 (vendor, nativeCode, category, message, traceId) 로 로깅되어야 함(운영 추적).","hangul_chars":51,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"* 운영전용 — 유저엔 generic(\"시스템 오류/잠시 후\"), 상세는 개발자·관리자 로그 추적용","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"① 우리 서비스가 현재 처리하는 에러핸들링 (codefErrorMessage switch 기준)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":66,"line_end":70,"block_type":"jsdoc","text":"② 쿠콘(전수 코드 보유) 기준으로 본, 우리가 부족한 핸들링.\n⚠️ 전제: 현재 비-codef 벤더는 native코드가 CF-* switch에 안 잡혀 default로 수렴 →\n   아래 '처리'로 표시된 카테고리도 provider=coocon/octover/hyphen 일 땐 실제로는 노출 안 됨.","hangul_chars":63,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"쿠콘 대표 코드/메시지","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":88,"line_end":88,"block_type":"jsdoc","text":"매트릭스 대상 벤더 (datahub 미구현 제외)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":91,"line_end":91,"block_type":"jsdoc","text":"테스트 시나리오 (웹 Tester 드롭다운과 동일, '(선택 안함)'/'직접입력…' 제외)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":113,"line_end":116,"block_type":"jsdoc","text":"중앙화된 사이클 단계 (유저 노출 기준, 벤더 무관 고정).\n벤더별 실제 API 호출 수는 달라도(쿠콘 SMS 5콜, codef 2콜) 이 단계로 정규화한다.","hangul_chars":46,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":124,"line_end":124,"block_type":"jsdoc","text":"벤더별 실제 API가 어느 중앙 단계에 속하는지 (보기용 매핑)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":152,"line_end":152,"block_type":"jsdoc","text":"하니스 raw call의 step 문자열 → 중앙 단계 추정 (catalog/coverage 분류용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":158,"line_end":158,"block_type":"line","text":"단, octover/hyphen은 1차 단어가 위에 포함됨","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":166,"line_end":172,"block_type":"jsdoc","text":"이미 \"아는\" 코드 (테스트 없이도 확보됨). (vendor, scenario) → 예상 native코드.\n - coocon: API 문서에 오류코드 전수 존재 → 다수 문서확보\n - codef : 우리 codefErrorMessage switch 에 이미 반영된 코드\n - octover/hyphen: 문서 공백 → 비움(테스트 필요)\n⚠️ \"예상(문서기반)\"이며, 테스트로 실제값/메시지를 확정한다.","hangul_chars":80,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"* '인증 시간 초과' coocon 전용코드 불명확 → 확인필요(테스트). (80004133은 '2차 세션 만료'로 분리)","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":188,"line_end":188,"block_type":"line","text":"기관 세션종료=VENDOR_ERROR","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":190,"line_end":190,"block_type":"line","text":"토큰 유효시간 만료=AUTH_EXPIRED (80002F20과 분리)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"* '만료/폐기 인증서' codef는 CF-12871(앱/인증서 통합)뿐 — 앱미설치와 코드충돌 → 확인필요","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":207,"line_end":207,"block_type":"line","text":"* 서비스정의서 4.오류코드표 기반 (errMsg '[코드]' 접두)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":211,"line_end":211,"block_type":"line","text":"* '이름-주민번호 불일치' → I0001-002는 '본인인증 실패' 일반코드(간편 미승인과 충돌) → 확인필요","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 'SMS 인증번호 오입력' → I0001-010은 세션종료와 코드중복(메시지의존) → 확인필요로 두고 테스트 확정","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":220,"line_end":224,"block_type":"jsdoc","text":"(vendor, nativeCode) → 통합 category(SNAKE_CASE) 매핑.\ncodef는 OUR_HANDLING 과 동일, coocon은 문서 딕셔너리 분류 기준.\noctover/hyphen은 테스트 후 catalog.annotate 로 채움.","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":227,"line_end":227,"block_type":"line","text":"CF-03002 = 1차 성공(추가인증 필요) — 실패 아님","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"(80002F31~3F 페이지변경)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"성공(자동연동). 실패코드는 테스트로 확보 후 보강","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":263,"line_end":264,"block_type":"line","text":"* (A) 업무 오류코드 — 서비스정의서 '4.오류코드표'. errMsg 에 '[코드]' 접두로 박혀옴.\n*     ⚠️ 일부 코드(I0001-010, LOGIN-001/003)는 메시지별로 의미가 갈림 → 메시지 병행 확인 필요.","hangul_chars":50,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":273,"line_end":274,"block_type":"line","text":"세션종료 기본 (메시지에 따라 인증실패/요청오류로도 쓰임)\n* (B) 전송계층 resCd (공통가이드 '(참고)응답코드 정의')","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/reference/mapping-reference.ts","lang":"js","line_start":292,"line_end":292,"block_type":"jsdoc","text":"③ 테스트로 직접 얻어내야 할 벤더별 미완(테스트필요) 리스트","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/seed.ts","lang":"js","line_start":3,"line_end":4,"block_type":"line","text":"* 하니스(로컬)에서 수집한 초기 데이터. S3가 비어있을 때(최초 부팅) 1회만 시드된다.\n* admin에서의 수정/삭제는 S3에 반영되며, .initialized 마커가 생긴 뒤 시드는 재적용되지 않는다.","hangul_chars":61,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* ECS는 컨테이너 로컬파일이 휘발 → catalog/coverage를 S3 JSON으로 영속.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":9,"line_end":9,"block_type":"line","text":"* 시드 1회 적용 마커 (이후 빈 상태여도 재시드 안 함)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 최근 raw 결과(메모리, 비영속)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 최초 부팅(마커 없음): 하니스 시드를 S3값에 병합(S3 키 우선) 후 마커 기록 → 재시드 방지.","hangul_chars":31,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* 없으면 빈값","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* 1) 카탈로그 = 오류코드 사전. 성공(c.ok) 제외.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":87,"line_end":87,"block_type":"line","text":"* 2) (vendor,scenario) 커버리지 — 인증타입별 최종 결과코드(성공 포함), authType당 last-wins","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":126,"line_end":126,"block_type":"jsdoc","text":"카탈로그 항목 수정: 메모/분류/유저메시지 + messages/scenarios 배열 직접 교체 가능","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":140,"line_end":140,"block_type":"jsdoc","text":"카탈로그 항목 삭제 (해당 코드 통째로 제거)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":150,"line_end":150,"block_type":"jsdoc","text":"커버리지 셀의 인증타입별 결과 1건 수정(코드/성공여부) — 오입력 정정용","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/store/treat-test.store.ts","lang":"js","line_start":164,"line_end":164,"block_type":"jsdoc","text":"커버리지 결과 1건 삭제. 결과가 모두 비면 셀 자체 제거. authType 미지정 시 셀 통째 삭제.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":12,"line_end":15,"block_type":"jsdoc","text":"진료내역 벤더 raw 테스트 API (관리자 전용).\n서버가 stg/prod VPC에서 NAT EIP로 벤더 호출 → 화이트리스트 통과. admin 숨김 라우트에서 사용.","hangul_chars":41,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":48,"line_end":48,"block_type":"jsdoc","text":"카탈로그 항목 수정(메모/분류/메시지/시나리오)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":55,"line_end":55,"block_type":"jsdoc","text":"카탈로그 항목 삭제","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":62,"line_end":62,"block_type":"jsdoc","text":"커버리지 셀의 인증타입별 결과 수정(코드/성공여부 정정)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":69,"line_end":69,"block_type":"jsdoc","text":"커버리지 결과/셀 삭제 (authType 미지정 시 셀 통째 삭제)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":76,"line_end":76,"block_type":"jsdoc","text":"흐름(Flow): 유저 단계 → 벤더 API 단계 → 각 단계 오류/정상","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.controller.ts","lang":"js","line_start":121,"line_end":121,"block_type":"jsdoc","text":"매핑 현황: 우리처리 / 추가필요 / 커버리지(인증타입별) / 전체코드 / 단계매핑","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.module.ts","lang":"js","line_start":11,"line_end":12,"block_type":"line","text":"* JwtModule(전역)·ConfigModule(전역)은 app.module에서 글로벌 등록되어 별도 import 불필요.\n* AdminJwtAuthGuard 의존성(JwtService, Reflector)도 전역에서 해결됨.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/treat-test.service.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"* 어댑터 getConfig()가 서버 env를 읽도록 1회 주입","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/codef.vendor.ts","lang":"js","line_start":16,"line_end":20,"block_type":"jsdoc","text":"코드에프(헥토) raw 어댑터.\n1차 certify / 2차 treat 모두 동일 treatMultiUrl 단건 호출.\n응답은 URL-encoded JSON → decodeURIComponent + JSON.parse. CF 정규화 없이 result.code/message 그대로 반환.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/codef.vendor.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"* 추가인증 필요 = 1차 성공","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/coocon.vendor.ts","lang":"js","line_start":25,"line_end":28,"block_type":"jsdoc","text":"쿠콘 raw 어댑터 (게이트웨이 다단계 호출). 오류코드는 문서에 전수 존재(8000x / GWSM 계열) → 본 하니스로 실제 발생코드 확인/검증.\n1차: 본인인증(+휴대폰인증_1). 2차: 휴대폰인증_2/OTP → 내진료정보열람 → 로그아웃(finally).","hangul_chars":71,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/coocon.vendor.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"* 2-1 인증 확정","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/coocon.vendor.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 2-2 내진료정보열람","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/crypto.ts","lang":"js","line_start":3,"line_end":4,"block_type":"line","text":"* ───────── 옥토버 RSA-OAEP(SHA-256) + \"doznenc_\" prefix ─────────\n* 출처: insuniverse-server/libs/octover/src/octover.crypto.ts (실호출 검증)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/crypto.ts","lang":"js","line_start":28,"line_end":29,"block_type":"line","text":"* ───────── 쿠콘 AES256-CBC (useAes=true 일 때) ─────────\n* 출처: insuniverse-server/libs/coocon/src/coocon-auth.service.ts","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/crypto.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* opaque 세션 블롭 (1차→2차 왕복). 벤더 무관 base64(JSON).","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/http.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"공통 POST. asText=true 면 응답을 문자열로 받음(코드에프 URL-encoded 대응). 에러도 응답바디를 그대로 반환.","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/http.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* 4xx/5xx 도 throw 하지 않고 바디 확보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/http.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"* 네트워크/타임아웃 등 (응답 자체 없음)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/hyphen.vendor.ts","lang":"js","line_start":27,"line_end":31,"block_type":"jsdoc","text":"하이픈/인포텍 raw 어댑터 (평문, api-cloud-key 헤더).\n2계층 오류: 전송 resCd + 업무 errYn/errMsg(free-text, 코드없음) → 본 하니스가 errMsg 원문 수집(문서 공백 보강 핵심).\n간편(EASY): 1차 앱푸시 → step_data → 2차 step_data 재전송. 휴대폰(SMS): 1차 captchaPass → userData → 2차 identityCheck+step_input.","hangul_chars":57,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/hyphen.vendor.ts","lang":"js","line_start":49,"line_end":49,"block_type":"line","text":"* 실행 타임아웃(초) — per-call(input) > config(HYPHEN_EXE_TIMEOUT) > 240. B0002-999 튜닝용","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/hyphen.vendor.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* errMsg 의 '[VALID-001]' 같은 업무코드 접두 추출 (서비스정의서 4.오류코드표)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/hyphen.vendor.ts","lang":"js","line_start":95,"line_end":95,"block_type":"line","text":"* 전송 오류면 resCd, 업무 오류면 errMsg의 [코드] 추출(서비스정의서 4.오류코드표)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/octover.vendor.ts","lang":"js","line_start":17,"line_end":17,"block_type":"line","text":"* 우리 loginTypeLevel(간편 상세) → 옥토버 loginType","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/octover.vendor.ts","lang":"js","line_start":22,"line_end":26,"block_type":"jsdoc","text":"옥토버(Dozn) raw 어댑터. PII는 RSA-OAEP 암호화.\n1차 phoneVerify/simpleAuthLogin → encInput. 2차 (loginResult + AB001) 체인.\n실패코드 미문서화 → 본 하니스가 out.data.{method}.code/msg 를 그대로 수집(문서 공백 보강 핵심).","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":4,"line_end":4,"block_type":"jsdoc","text":"simple=간편인증 / mobile=휴대폰SMS / cert=공동인증서(코드에프·쿠콘)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":7,"line_end":7,"block_type":"jsdoc","text":"클라(Flutter)에서 들어오는 테스트 요청","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":12,"line_end":12,"block_type":"jsdoc","text":"간편 상세구분 1카카오/2페이코/3삼성패스/4KB/5PASS/6네이버/7신한/8토스","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":14,"line_end":14,"block_type":"jsdoc","text":"휴대폰 통신사 0SKT/1KT/2LGU+/3~5알뜰","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":17,"line_end":17,"block_type":"jsdoc","text":"주민등록번호 13자리(앞6+뒤7)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"조회 시작/종료 YYYYMMDD (미지정 시 최근 5년)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":23,"line_end":23,"block_type":"jsdoc","text":"민감상병 표시 '1'(표시)/'0'","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":25,"line_end":25,"block_type":"jsdoc","text":"하이픈 실행 타임아웃(초) — 미지정 시 config(HYPHEN_EXE_TIMEOUT) 또는 240. B0002-999 튜닝용","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 1차 응답으로 받은 세션 블롭(opaque, 그대로 왕복)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* SMS 인증번호 (mobile)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 간편 승인여부 '1'/'0' (codef)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"테스트 시나리오 라벨(예: '주민번호 오입력', '앱 미설치') — 카탈로그 집계용","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":37,"line_end":37,"block_type":"jsdoc","text":"벤더 호출 1건의 raw 기록","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"* '토큰' | 'certify' | '본인인증' | 'AB001' | ...","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"* PII 마스킹된 요청","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 벤더 raw 응답 (정규화 X)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":49,"line_end":49,"block_type":"jsdoc","text":"certify/treat 1회 처리 결과","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":56,"line_end":56,"block_type":"jsdoc","text":"최종 판정 native 코드/메시지 (실패면 실패 step 기준)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":59,"line_end":59,"block_type":"jsdoc","text":"1차 성공 시 2차로 넘길 세션 블롭","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":61,"line_end":61,"block_type":"jsdoc","text":"2차 성공 시 수집 데이터 (요약)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":63,"line_end":63,"block_type":"jsdoc","text":"모든 하위 벤더 호출 raw 기록","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":67,"line_end":67,"block_type":"jsdoc","text":"모든 벤더 어댑터 공통 계약","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":84,"line_end":84,"block_type":"jsdoc","text":"최근 5년(1825일) 조회기간 기본값 (YYYYMMDD)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat-test/vendors/types.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"* 공동인증서","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":13,"line_end":21,"block_type":"jsdoc","text":"★보안(헤드라인 #1 완화): /treat/certify 는 비로그인 capability(altCode/agcCode) 기반 공개 엔드포인트라\n  세션 가드를 못 붙인다(B2C·알림톡 비로그인). 대신 폰/IP 단위 레이트리밋으로 \"남 명의 신원 살포\" 남용을\n  막는다. (조사 결론: certify 남용은 인증가드가 아니라 레이트리밋 레이어가 맞다.)\n\n  ★게이트(무중단/실유저 보호): RATE_LIMIT_CERTIFY_PER_MIN=0(기본)이면 무제한 = 동작 무변. >0 일 때만 활성.\n  실유저(가족 공유IP·정상 재시도)를 자르지 않게 임계값은 운영자가 신중히 정해 켠다.\n  ★Redis 장애 시 fail-OPEN(통과) — 인프라 장애로 실유저를 막지 않는다('실유저 안 자르기' 원칙).","hangul_chars":179,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"게이트 OFF = 동작 무변","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"식별 불가면 통과(차단 안 함)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"1분 윈도우","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"레이트리밋 차단은 전파","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/certify-rate-limit.guard.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"★Redis 장애 = fail-open(실유저 안 자름)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/coocon-bypass.controller.ts","lang":"js","line_start":17,"line_end":23,"block_type":"jsdoc","text":"진료수집(쿠콘) 바이패스 — 외부 서비스(보상닥터)용.\n - 인증: ClientBasicAuthGuard (tn_client CODE:PASS). req.user.username = cliCode.\n - 동작: 외부가 보낸 쿠콘 봉투를 우리 인증키만 주입(미노출)해 쿠콘 게이트웨이로 그대로 전달.\n - 슬롯: 본인인증(세션 시작) 시 client별 동시 슬롯 예약(TTL 자동만료). 초과 시 429.\n   (MVP: TTL 자동만료로 동시건수 상한 보장. 즉시해제는 2단계)","hangul_chars":104,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/coocon-bypass.controller.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 세션 시작(본인인증) 시 client별 슬롯 예약. TTL(10분)로 동시건수 상한 보장.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-car-canary.util.ts","lang":"js","line_start":10,"line_end":10,"block_type":"jsdoc","text":"명시된 자동차 항목은 허용 공급자에서만 보존하고, 하이픈 등 나머지에서는 제거한다.","hangul_chars":35,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"* providerFromTag는 기존 import 경로(이 파일) 호환 위해 re-export","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":23,"line_end":23,"block_type":"line","text":"* 풀 1개 항목 (configuration.treatPool)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"* floor(분당한도 / 플로우비용) = 동시 진행 가능 플로우","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* 라우팅 우선순위(낮을수록 먼저) — 1차 정렬 기준","hangul_chars":18,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 동순위 tiebreaker(비용 오름차순)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* 분당 rate-limit(타임) 적용 여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* rate ON 시 분당 허용건수 (= maxFlows 공식 재사용)","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"* 공급자측 장애 코드 — 1차 실패가 이 코드면 다음 공급자로 폴백(사용자 입력오류는 폴백 안 함)","hangul_chars":36,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":37,"line_end":40,"block_type":"line","text":"* 단계별 TTL — 단계 전환마다 refresh로 다시 잰다(1차 지연이 OTP/수집 타이머에 영향 안 주게).\n*  RESERVE: 1차 호출 axios timeout(300s) + 여유 → 1차 응답 도중 슬롯 만료 방지(백업).\n*  OTP    : CF-03002 시점 refresh. OTP 제한 170s + 여유. 미입력 이탈은 여기서 3분에 회수.\n*  COLLECT: OTP 입력(treatCompare) 시 refresh. 수집 300s + 안전 120s.","hangul_chars":73,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":41,"line_end":41,"block_type":"line","text":"* 6분 (1차 호출 백업)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":45,"line_end":52,"block_type":"jsdoc","text":"멀티 공급자 디스패처 — TreatScraper 데코레이터.\n1차: 비용 싼 공급자부터 자리(예약) 잡히는 곳 선택 → 호출 → jti에 공급자 태깅. 다 차면 CF-BUSY.\n2차: jti 태그로 같은 공급자(sticky) 복원 → 호출 → 예약 정산.\ntreatProvider='multi' 일 때 TreatService가 이걸 사용.\n\n⚠️ 대기열(만석 시 유저 보류)은 미구현 — 현재는 CF-BUSY(재시도). 큐는 클라 연동 필요(다음 단계).","hangul_chars":100,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* 공급자 설정(DB, 단가오름차순, env 폴백) → 실제 스크래퍼 매핑 + 비용 오름차순 정렬","hangul_chars":29,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* rate ON 시 동일 공식을 '분당 허용건수'로 사용","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"* 라우팅 우선순위 = tprSort 오름차순, 동순위면 단가 오름차순(tiebreaker).","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"* [2단계] 재요청 + 유효 입장권 → hold된 슬롯으로 바로 입장(새치기 없는 확정 자리).","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"* 처리됨(성공/사용자측실패). 공급자측 폴백이면 아래 일반루프.","hangul_chars":25,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":134,"line_end":135,"block_type":"line","text":"* [2단계] 신규 요청: 큐 대기자가 있으면 '여유 슬롯(대기자 몫 제외)'이 있을 때만 직접 시도.\n*   여유 없으면 곧장 줄 세움 → 큐 맨앞을 제치는 새치기 차단.","hangul_chars":55,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":145,"line_end":145,"block_type":"line","text":"* rate-limit(타임) ON 공급자: 최근 60초 ratePerMin건 초과면 건너뛰고 다음 공급자(폴백) → 벤 방지","hangul_chars":26,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"line","text":"* 만석 → 다음 공급자","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 1차 라우팅 공급자를 응답에 부착 (성공·실패 공통) → 로그에서 인증실패도 벤더 귀속","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"* 성공: jti에 공급자+예약 태깅 (2차에서 sticky 복원)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"* CF-03002 시점 = OTP 대기 시작 → TTL을 OTP(3분)로 재설정 (1차 지연 분리, 미입력 이탈 3분 회수)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":178,"line_end":178,"block_type":"line","text":"* 입장 확정 → 큐 제거","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"* 인증 실패: 2차 없음 → 즉시 예약 반납 (벤더는 위에서 부착됨)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":184,"line_end":184,"block_type":"line","text":"* 공급자측 장애(IP차단 등)면 다음 공급자로 폴백, 사용자측 실패(입력오류 등)는 그대로 반환","hangul_chars":35,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":191,"line_end":191,"block_type":"line","text":"* 사용자측 실패 → 큐 제거(재시도 안 함)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":192,"line_end":192,"block_type":"line","text":"* 실패 응답 그대로","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":195,"line_end":195,"block_type":"line","text":"* 예외(타임아웃/네트워크)도 공급자 장애로 간주 → 다음 공급자 폴백 (마지막까지 실패 시 아래 큐/BUSY)","hangul_chars":37,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":201,"line_end":203,"block_type":"line","text":"* 전 공급자 만석.\n* [1단계] 재요청(reqQueueId 보유)이고 아직 큐에 살아있으면 → 기존 순번 유지(재enqueue 금지).\n*   READY 받고 재요청했다가 또 만석인 경우 새 큐ID로 맨뒤 추락하던 버그 방지.","hangul_chars":60,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":208,"line_end":209,"block_type":"line","text":"* 신규이거나, reqQueueId가 이미 만료/이탈로 큐에서 빠진 경우 → 새로 줄 세움.\n*   (죽은 재요청도 반드시 재진입시켜야 '큐에도 없고 입장도 못 하는 영구 미아' 방지)","hangul_chars":57,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":215,"line_end":215,"block_type":"line","text":"* Redis 없어 큐 불가 → 폴백으로 BUSY","hangul_chars":9,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":220,"line_end":220,"block_type":"line","text":"* 대기열 진입 응답 (CF-QUEUE + queueId). 클라는 queueId로 순번 폴링 후 READY면 certify 재요청.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":241,"line_end":242,"block_type":"line","text":"* [2단계] 입장권으로 hold된 슬롯에 입장. 성공/사용자측실패면 응답 반환,\n*   공급자측 폴백 필요(또는 공급자 소멸)이면 null → 호출부의 일반 reserve 루프로.","hangul_chars":52,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":251,"line_end":251,"block_type":"line","text":"* 풀에서 사라진 공급자 → hold 반납","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":255,"line_end":257,"block_type":"line","text":"* 직접 경로와 대칭: 1차 호출 전 hold를 RESERVE_TTL로 끌어올림.\n*   hold는 18초(ADMIT_TTL)인데 codef 1차가 그보다 오래 큐잉되면 호출 도중 hold 만료 →\n*   그 틈에 다른 요청이 슬롯 차지 + promoteHold(plain zadd)가 되살려 maxFlows+1 초과. (XX라 살아있을 때만 연장)","hangul_chars":65,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":268,"line_end":269,"block_type":"line","text":"* 성공: hold를 정식 예약으로 승급(=CF-03002 시점) → OTP TTL로 + jti 태깅(r=holdMember) + 큐 제거\n*   score가 OTP(3분)로 점프 → slotStat의 score-window에서 '대기중 hold'와 자동 구분(유령 hold 제외)","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":286,"line_end":286,"block_type":"line","text":"* 실패 → hold 반납","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":289,"line_end":289,"block_type":"line","text":"* 다른 공급자 자리 잡도록 일반 루프로","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":291,"line_end":291,"block_type":"line","text":"* 사용자측 실패 → 큐 제거","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":300,"line_end":301,"block_type":"line","text":"* [2단계] 신규 요청 여유 슬롯 = freeSlots − (살아있는 대기자 − hold 받은 수).\n*   hold 받은 맨앞은 이미 슬롯에 반영(freeSlots에서 빠짐)되므로 대기자 수에서 제외해 이중차감 방지.","hangul_chars":54,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":329,"line_end":329,"block_type":"line","text":"* 원래 jti 복원 (공급자 어댑터가 자기 세션을 디코딩하도록)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":332,"line_end":332,"block_type":"line","text":"* OTP 입력(treatCompare) → 수집 진입 → TTL을 수집(7분)으로 재설정. 살아있는 슬롯만 갱신(XX), 죽었으면 no-op.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":337,"line_end":337,"block_type":"line","text":"* 마지막 외부호출 끝 → 슬롯 반납","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts","lang":"js","line_start":338,"line_end":338,"block_type":"line","text":"* 처리업체 영속화","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":2,"line_end":3,"block_type":"line","text":"외부 공급자 SDK 모듈 로드 차단 — factory mock (automock은 실제 require하다 drizzle에서 실패).\n생성자 주입 자리만 채우므로 빈 클래스로 충분.","hangul_chars":39,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":12,"line_end":14,"block_type":"line","text":"* dispatcher가 reservation을 '올바른 시점·TTL'로 호출하는지 실제 실행으로 검증.\n*   reservation = 실제(TEST_REDIS_URL, 기본 로컬 redis 6380), 나머지 의존성은 mock. scraper는 응답을 흉내.\n* 단계별 TTL: 1차 CF-03002→OTP(180s) / 2차 treatCompare→COLLECT(420s) / 완료→settle.","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"원래 세션 보존","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"2차 호출 진입 순간의 TTL을 포착 (settle 전)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":116,"line_end":116,"block_type":"line","text":"원래 세션으로 복원됐는지","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"공급자엔 원래 jti가 전달","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"완료 → 슬롯 반납","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":146,"line_end":146,"block_type":"line","text":"20슬롯 선점유","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":155,"line_end":155,"block_type":"line","text":"만석이라 호출 안 됨","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","lang":"js","line_start":156,"line_end":156,"block_type":"line","text":"초과 점유 없음","hangul_chars":6,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":5,"line_end":6,"block_type":"line","text":"* 오버플로 대기열 — 실 redis 대상. FIFO 순번 / 하트비트 생존·이탈 / 앞막힘 정리 /\n*   issueAdmit 새치기 차단(맨앞 슬롯 hold) / dropped 집계 / 만석 시 READY 보류.","hangul_chars":41,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"* 슬롯을 모두 채워(만석) 입장이 막힌 상태에서 순번 표시를 검증","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* a용 슬롯이 reservation에 hold로 잡힘 → 신규 요청이 가로채지 못함","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"이탈(폴링 끊김) 시뮬","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"맨앞 a 이탈","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"b 폴링 → 앞의 죽은 a 정리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"이탈 기록","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"b가 맨앞 + 슬롯 여유","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"맨앞 생존","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"중간 → 이탈시킬 대상","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"중간 b 이탈","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":101,"line_end":101,"block_type":"line","text":"* full prune 차단(방금 돈 것처럼) → pruneFront만 동작","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":103,"line_end":103,"block_type":"line","text":"pruneFront: 살아있는 a에서 멈춤 → b 안 잡힘","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":104,"line_end":105,"block_type":"line","text":"중간 좀비 잔존\n* 단, 실시간 집계는 prune 없이도 유령 제외","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* full prune 허용 → 전체 스캔이 중간 좀비 제거 + dropped 집계","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"중간(이탈 예정)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"b 중간 이탈","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"맨앞 a 정상 입장/이탈 → b가 맨앞으로","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":122,"line_end":122,"block_type":"line","text":"폴링 → 죽은 맨앞 b를 pruneFront가 제거","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"좀비 제거","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":124,"line_end":124,"block_type":"line","text":"산 사람 c가 맨앞 + 슬롯여유","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":142,"line_end":142,"block_type":"line","text":"* a 폴링 끊김(백그라운드) 시뮬 — alive는 유지","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":143,"line_end":143,"block_type":"line","text":"* a active 없음 → b가 활성 맨앞으로 admit","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":145,"line_end":145,"block_type":"line","text":"* a 순번 보존(큐 유지)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":150,"line_end":150,"block_type":"line","text":"* 1자리만 남김","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":153,"line_end":153,"block_type":"line","text":"* a가 마지막 1자리 hold","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"* 자리 없음 → a 자리 못 뺏음","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"* 2자리 여유","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":163,"line_end":163,"block_type":"line","text":"* 1번째 자리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"* 2번째 자리 (병렬 충전)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"* 자리 소진 → 대기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":171,"line_end":171,"block_type":"line","text":"* a 백그라운드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","lang":"js","line_start":173,"line_end":173,"block_type":"line","text":"* a 복귀 폴링 → active 부활 → a admit(슬롯 여유)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":8,"line_end":11,"block_type":"line","text":"* 하트비트 유효시간. 폴링 주기(2s)보다 충분히 길게 — 모바일 백그라운드/앱전환으로\n*   브라우저가 폴링 setTimeout을 스로틀(분 단위)하면 짧은 TTL은 정상 대기자를 이탈로 오판한다.\n*   90초면 잠깐 화면 끄거나 앱 전환해도 큐 유지(복귀 시 EXPIRED→처음으로 튕기는 문제 완화).\n*   창 닫기(진짜 이탈)는 sendBeacon leave로 즉시 제거되므로 이 값이 길어도 좀비는 안 쌓인다.","hangul_chars":124,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":13,"line_end":15,"block_type":"line","text":"* admit(슬롯 배정) 자격 = '최근 폴링(활성)' 여부. alive(큐 생존)보다 짧게.\n*   백그라운드로 폴링이 끊긴 맨앞은 active가 만료돼 admit 대상에서 빠진다(슬롯 안 막음).\n*   단 alive(90초)로 큐 순번은 유지 → 복귀해 폴링하면 다시 활성 맨앞. 폴링 2초 × 6.","hangul_chars":76,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 차례 + 자리 있음 → 클라가 인증 재요청","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"* 큐에 없음(이탈/만료/완료)","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":36,"line_end":40,"block_type":"line","text":"* 전 공급자 만석 시 유저를 줄 세우는 오버플로 대기열 (Redis).\n* - 순서: 정렬셋(score=진입시각) FIFO\n* - 생존: 클라 폴링마다 alive 키 TTL 갱신. 끊기면(이탈) 자동 만료 → 큐에서 제거\n*   → 떠난 유저에겐 차례가 와도 인증 안 쏨(벤더 호출 보호)\n* - 차례: 살아있는 맨 앞 + 자리(슬롯) 있으면 READY → 클라가 certify 재요청","hangul_chars":97,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":55,"line_end":55,"block_type":"line","text":"* 끊긴 동안 명령 큐잉 → 재연결 후 처리","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":57,"line_end":57,"block_type":"line","text":"* idle TCP 끊김 방지","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 자동 재연결 백오프","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"* admit 자격용 — 최근 폴링 여부. 만료 시 백그라운드로 간주해 admit 대상에서 제외(슬롯 안 막음).","hangul_chars":32,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* 큐 진입 → queueId. 클라는 이후 status를 주기적 폴링.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* Redis 없으면 큐 비활성","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* 진입=활성(첫 폴링 전 백그라운드 오인 방지)","hangul_chars":17,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* 상태 폴링(=하트비트). 본인 생존 갱신 → 죽은 앞사람 정리 → 순번/READY 판정.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* 본인은 방금 폴링했으니 생존 갱신","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":87,"line_end":87,"block_type":"line","text":"* 이미 만료(오래 끊김) → 큐에서 제거","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"* 큐 생존(이탈 방지)","hangul_chars":7,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":92,"line_end":93,"block_type":"line","text":"* admit 자격(최근 폴링)\n* [3단계] 맨앞 죽은 대기자만 즉시 정리(앞막힘 방지) + 전체 스캔은 throttle(폴링당 O(N) 부하↓)","hangul_chars":35,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":100,"line_end":103,"block_type":"line","text":"* 내 앞의 '활성' 대기자 수 < 여유 슬롯 수 → 빈 슬롯을 병렬로 채운다(여유 N개면 앞 N명 동시 READY).\n*   기존엔 활성 맨앞 1명만 admit → 슬롯이 N개 비어도 1명씩 직렬 입장(대기열 적체 원인)이었다.\n*   issueAdmit이 maxFlows reserve 게이트라, 동시 시도해도 실제 자리만큼만 hold 발급(과다입장 불가).\n*   백그라운드로 폴링 끊긴 앞사람은 active가 만료돼 카운트에서 빠진다(슬롯 안 막음).","hangul_chars":121,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":111,"line_end":114,"block_type":"line","text":"* 내 앞(rank 이전)에 active(최근 폴링)한 대기자가 하나라도 있나. 있으면 그 사람이 먼저 admit.\n*   앞이 전부 백그라운드(active 만료)면 false → 내가 활성 맨앞으로 슬롯 받음.\n*   ★ Lua로 맨앞부터 스캔하며 첫 active에서 즉시 종료(early-exit) — 정상(맨앞 active)이면\n*     1회 EXISTS로 끝나 폴링당 O(rank) 부하를 피한다(피크 200명에서 redis 보호).","hangul_chars":95,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"* 진짜 맨앞이면 앞사람 없음","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":134,"line_end":137,"block_type":"line","text":"* 내 앞(rank 이전)의 '활성(최근 폴링)' 대기자 수. 여유 슬롯과 비교해 병렬 입장 폭을 정한다.\n*   anyActiveAhead(맨앞 1명만)와 달리 끝까지 세어, 여유 슬롯이 N개면 앞 N명이 동시에 READY.\n* 앞사람 중 active(폴링중) AND admit(hold) 아직 안 받은 수 = '나보다 먼저 들어갈 미입장 대기자'.\n*   admit 보유자는 이미 슬롯 hold로 freeSlots에서 빠졌으므로 카운트에서 제외(이중차감 방지).","hangul_chars":113,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":161,"line_end":162,"block_type":"line","text":"* 공급자 풀 전체 여유 슬롯 수 = Σ max(0, maxFlows − inflight). (metrics와 동일 공식, 경량 버전)\n*   inflight은 hold(18초 임시)도 포함 → 실제 admit 가능 자리를 정확히 반영.","hangul_chars":39,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":172,"line_end":172,"block_type":"line","text":"* 입장권 발급용 풀 (dispatcher pool과 동일 공식: maxFlows=floor(한도/비용), ratePerMin=maxFlows)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":186,"line_end":186,"block_type":"line","text":"* 큐 이탈 (창 닫기 best-effort / 인증 재요청 성공 시 제거)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":194,"line_end":195,"block_type":"line","text":"* [1단계] 재요청 시 이 큐ID가 아직 유효한 대기 상태인지 — 살아있으면 alive 갱신 후 true.\n*   true면 dispatcher가 기존 순번 유지(재enqueue 금지), false면 새로 줄 세움(영구 미아 방지).","hangul_chars":51,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"* 이탈/만료","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":200,"line_end":201,"block_type":"line","text":"* 이미 큐에서 빠짐\n* 재요청 자체가 생존 신호 → alive 갱신(폴링 공백 동안의 이탈 오판 방지)","hangul_chars":32,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":206,"line_end":206,"block_type":"line","text":"* [2단계] 살아있는(하트비트 유효) 대기자 수 — 신규 여유분 계산용(경량).","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":217,"line_end":217,"block_type":"line","text":"* 죽은(이탈) 엔트리 일괄 제거 — 앞사람이 죽어있으면 뒷사람이 못 올라오므로 정리 필요","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"* 이탈(하트비트 끊겨 중도 포기) 기록 — score=이탈시각. 모니터링 집계용","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":230,"line_end":231,"block_type":"line","text":"* [3단계] 맨앞 죽은 대기자만 정리 — 살아있는 첫 맨앞을 만나면 멈춤(경량, 앞막힘 방지).\n*   죽은 맨앞이 뒷사람을 막는 문제만 핫패스에서 해결하고, 중간/뒤 좀비는 전체 prune에 위임.","hangul_chars":66,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":233,"line_end":233,"block_type":"line","text":"* 앞 10개까지 검사","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":235,"line_end":235,"block_type":"line","text":"* 살아있는 맨앞 → 정리 종료","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":242,"line_end":243,"block_type":"line","text":"* [3단계] 전체 prune은 비싸므로 인스턴스당 10초 1회로 throttle.\n*   뒤쪽 좀비는 순번에 영향 없어 즉시성 불필요(모니터 집계 정확도만 약간 지연).","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":252,"line_end":252,"block_type":"line","text":"* 공급자 풀 중 자리(슬롯) 하나라도 있나 — 디스패처와 동일한 DB 풀(getPool) 기준 (헛 READY 방지)","hangul_chars":29,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":262,"line_end":262,"block_type":"line","text":"* 모니터링용 큐 전체 지표: 인원/유령/이탈 + 대기시간(최장·평균·분포) + 현재 가용 슬롯","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":273,"line_end":273,"block_type":"line","text":"* 1시간 지난 기록 정리","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":274,"line_end":274,"block_type":"line","text":"* 최근 30분 이탈","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":276,"line_end":276,"block_type":"line","text":"* 현재 즉시 받을 수 있는 슬롯 수(가용) + 전체 수용량 — \"왜 대기가 생기나\" 설명","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":284,"line_end":284,"block_type":"line","text":"* 대기열 엔트리(진입시각=score)로 대기시간 계산","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-queue.service.ts","lang":"js","line_start":297,"line_end":297,"block_type":"line","text":"* 유령(하트비트 끊김) 제외 — 실제 대기자만 집계","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":4,"line_end":5,"block_type":"line","text":"* 슬롯 예약 서비스 — 실 redis(6380) 대상 동시성·TTL·hold 동작 검증.\n*   reserve 하드캡 / refresh(ZADD XX) purge거부 / OTP 자동회수 / slotStat score-window / admit.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"원래 TTL 경과했지만 연장됨","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"score 만료 (lazy — 아직 물리 잔존)","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"다른 호출이 ZREMRANGEBYSCORE로 회수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"XX 대상 없음","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"입장 확정 → score 점프","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"확정자는 hold 카운트서 제외","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":6,"line_end":10,"block_type":"line","text":"* 공급자별 진행중 플로우 예약 카운터 (Redis, 멀티 인스턴스 공유).\n* 점유 = 진행중 플로우 수. 1차에서 reserve, 2차 완료/실패 시 settle.\n* 이탈(폰인증 방치)은 정렬셋 score(만료시각)로 자동 purge → 슬롯 자동 회수(TTL).\n*\n* reserve: Lua 원자연산 — 만료분 제거 → 현재수 < maxFlows 면 추가(성공) / 아니면 실패.","hangul_chars":87,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 만료분 purge 후, 여유 있으면 예약(ZADD), 없으면 0","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":27,"line_end":28,"block_type":"line","text":"* sliding window rate-limit(60초): 창 밖 정리 → 창 내 건수 < perMin 이면 기록(허용)/아니면 거부.\n* 기록은 settle하지 않음 — 60초 자동 만료가 곧 '점유 유지'(이탈해도 60초 hold = codef rate 보호).","hangul_chars":45,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* 끊긴 동안 명령 큐잉 → 재연결 후 처리 (분산 쏠림 방지)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":47,"line_end":47,"block_type":"line","text":"* idle TCP 끊김 방지","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":48,"line_end":48,"block_type":"line","text":"* 자동 재연결 백오프","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 예약 시도. 성공 시 resvId, 실패(만석) 시 null. Redis 없으면 무제한 허용(폴백).","hangul_chars":22,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"* 폴백: 카운트 안 함","hangul_chars":7,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* Redis 장애 시 막지 않고 통과(가용성 우선)","hangul_chars":14,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* 안전 기능용 예약. Redis 미설정/장애 시에도 통과시키지 않는다.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":106,"line_end":106,"block_type":"line","text":"* 예약 해제 (2차 완료/실패 시)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":114,"line_end":115,"block_type":"line","text":"* 단계 전환 시 예약 만료시각 갱신 (CF-03002→OTP대기, OTP입력→수집).\n* ZADD XX: 존재하는 멤버만 갱신 → 이미 만료(purge)된 슬롯은 되살리지 않음(동시성 안전).","hangul_chars":47,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 현재 점유(진행중 플로우 수) — 모니터링용","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":140,"line_end":141,"block_type":"line","text":"* 분당 rate-limit(sliding 60초). 허용 시 호출 기록 후 true, 한도 도달 시 false.\n* 슬롯(reserve)과 별개 — rate ON 공급자는 \"최근 60초 perMin건\"으로 호출 자체를 제한(벤 방지).","hangul_chars":41,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":146,"line_end":146,"block_type":"line","text":"* 최근 60초 실제 호출수(분당 사용량) — 모니터링용. rate-limit 근접도 표시.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":155,"line_end":155,"block_type":"line","text":"* Redis 없으면 통과(가용성 우선)","hangul_chars":10,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"* 60초 창 밖 제거 기준","hangul_chars":7,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":163,"line_end":163,"block_type":"line","text":"* score = 호출시각","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"* Redis 장애 시 막지 않고 통과","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":174,"line_end":175,"block_type":"line","text":"*===================== [2단계] 입장권(admit) · 슬롯 hold =====================\n* 입장권 TTL — status 폴링(2s)+READY 수신+재요청 왕복 여유(느린망). 미사용 시 hold 자동 회수.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":181,"line_end":183,"block_type":"line","text":"* 공급자 1곳 원자 hold: 슬롯 여유 AND (rate OFF | rate창<perMin) 이면\n* resv에 hold 멤버 추가(+rate ON이면 rate 1건 선점). 성공 1 / 실패 0.\n*   hold 멤버는 'hold:' 접두사 → freeSlots 계산 시 정식예약과 구분.","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":200,"line_end":200,"block_type":"line","text":"* 입장권 원자 소비(GET+DEL) — Redis 6.2 GETDEL 의존 제거용 Lua.","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":207,"line_end":208,"block_type":"line","text":"* 맨앞 대기자에게 슬롯 hold 시도 → 성공 시 입장권 발급 + hold정보 반환, 실패 null.\n*   pool: 비용오름차순 [{key, maxFlows, rateEnabled, ratePerMin}]. 이미 발급돼 있으면 멱등.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":216,"line_end":216,"block_type":"block","text":"손상 시 아래에서 재발급","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"* 미사용 시 회수 시점","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":240,"line_end":240,"block_type":"line","text":"* 전 공급자 여유 없음 → WAITING 유지","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":243,"line_end":243,"block_type":"line","text":"* 입장권 원자 소비. 있으면 hold정보(provider/holdMember/rateMarked), 없으면(만료/이미소비) null.","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"line","text":"* hold 슬롯 → 정식 예약 승급: 멤버 유지하고 만료시각만 RESERVE_TTL로 연장(입장 확정).","hangul_chars":26,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":266,"line_end":268,"block_type":"line","text":"* 공급자별 점유 상세 — 총점유(inflight) / 그중 '대기중' hold 수.\n* score-window 구분: 대기중 hold(score≤now+ADMIT_TTL) vs 확정 hold(promoteHold로 score가 OTP/수집 TTL로 점프).\n*   확정자가 holdCount에 남으면 freeRoom 과대→대기자 새치기 발생. score로 걸러 제외(rename은 jti.r 고아 누수라 금지).","hangul_chars":62,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-reservation.service.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 대기중 hold만 카운트 — 확정자는 score가 OTP/수집 TTL로 점프해 자동 제외","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-tag.util.ts","lang":"js","line_start":1,"line_end":3,"block_type":"line","text":"* 디스패처 ↔ 공급자 sticky 태그(jti base64) — 순수 인코딩 유틸.\n*   treat-dispatcher.service에서 분리: log-treat 등에서 import해도 모듈 순환참조가\n*   생기지 않도록(의존 없는 순수 함수만 모음).","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-tag.util.ts","lang":"js","line_start":5,"line_end":5,"block_type":"line","text":"* 라우팅된 공급자 키","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/dispatch/treat-tag.util.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 1차 인증 응답 jti 태그에서 라우팅된 공급자 키 추출 (멀티 디스패처 전용, 단일 모드면 null)","hangul_chars":32,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":1,"line_end":3,"block_type":"line","text":"* 진료내역 4벤더(codef·coocon·octover·hyphen) 통합 에러 택소노미.\n*   모든 벤더 native 코드는 아래 category 중 하나로 수렴 → 유저/알림톡 메시지·재시도성의 단일 출처.\n*   설계 출처: server/docs/treat-vendor-error-handling.md (1·3장)","hangul_chars":51,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 성공/추가인증(CF-00000·CF-03002 등) — 실패 아님","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 사이트 노출용 짧은 메시지 (문서 1장)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 알림톡 발송용 메시지 (기존 codefErrorMessage와 동일 톤 — 문서 6-1)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* user=구체 메시지 노출 / ops=유저엔 generic, 상세는 로그·관리자용","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":35,"line_end":38,"block_type":"line","text":"* 동일 입력으로 자동 재시도하면 성공 가능성이 있는가.\n*   true=일시/시스템 사유(타임아웃·기관오류·네트워크 등) → 재시도 유도.\n*   false=사용자 입력·조건 변경이 필요(오입력·연령·앱미설치 등) → 실패 단정.\n*   ★ 갭 A 해결: '재시도 가능 오류'와 '진짜 실패'를 코드 한 곳에서 구분.","hangul_chars":97,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* category → 메타. 알림톡 메시지는 기존 codefErrorMessage 문자열을 그대로 보존.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 앱에서 다시 승인하면 됨","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* 사용자가 번호를 정정해야 함","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-category.ts","lang":"js","line_start":150,"line_end":150,"block_type":"line","text":"* 기존 default와 동일","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":6,"line_end":7,"block_type":"line","text":"* 기존 treat.event-handler.ts codefErrorMessage switch의 (코드→알림톡메시지) 스냅샷.\n*   resolve의 alimtalkMessage가 이와 동일해야 교체 시 회귀 없음(trailing space는 정리).","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"실측: 주민번호 형식오류","hangul_chars":10,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":57,"line_end":57,"block_type":"line","text":"실측: 정보 불일치","hangul_chars":7,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"실측: 통신사 미선택","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":92,"line_end":92,"block_type":"line","text":"* 문서 3-4 핵심: errYn=Y 업무오류가 result.code엔 안 실리고 errMsg에 묻힘","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":103,"line_end":103,"block_type":"line","text":"* prod 실측(2026-06-08): resCd=0000 errYn=Y, errMsg에 보안문자 불일치 코드가 묻힘","hangul_chars":15,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"통신코드 E201 유지","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","lang":"js","line_start":122,"line_end":122,"block_type":"line","text":"유저엔 generic이라도 메시지는 있음","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"* 매핑에 사용된 실제 코드(hyphen은 errMsg에서 끌어올린 업무코드일 수 있음)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.ts","lang":"js","line_start":15,"line_end":15,"block_type":"line","text":"* hyphen errMsg의 '[업무코드]' 접두 추출. 통신 0000+errYn=Y면 진짜 코드가 여기 있음(문서 3-4 주의).","hangul_chars":25,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.ts","lang":"js","line_start":22,"line_end":23,"block_type":"line","text":"* (vendor, native코드[, errMsg]) → 통합 분류 + 유저/알림톡 메시지 + 재시도성.\n*   미수록 코드는 UNKNOWN(ops generic)으로 폴백. 모든 호출부의 단일 출처.","hangul_chars":38,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* hyphen 보정: 업무코드([코드])가 매핑에 있으면 통신코드보다 우선","hangul_chars":23,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-resolver.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* 성공/추가인증 여부 — 실패 분기 전 빠른 판정용","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":3,"line_end":4,"block_type":"line","text":"* (vendor, native코드) → category 매핑. 출처: server/docs/treat-vendor-error-handling.md (3장)\n*   미수록 코드는 resolve에서 UNKNOWN으로 폴백.","hangul_chars":19,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":10,"line_end":10,"block_type":"line","text":"* 추가인증 필요 — 실패 아님(2차 OTP 오입력 특수처리는 호출부)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* ---- coocon (3-2): Output.ErrorCode / Common.Result_cd (8자리 hex 계열) ----","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"* ---- prod 실측 현행화(2026-06-29) ----","hangul_chars":5,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 비정상 접속 → 사이트 보안정책 차단","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":71,"line_end":71,"block_type":"line","text":"* 잘못된 생년월일","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* 잘못된 SAS_SessionID(세션 선행처리 누락)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 정의되지 않은 오류(쿠콘 게이트웨이)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 우리측 axios 300초 타임아웃/통신 끊김(공통 래퍼코드)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":77,"line_end":79,"block_type":"line","text":"* ---- octover (3-3): out.data[method].code / out.code (7자리 숫자, DOZN 공통 오류코드) ----\n*   출처: octover 오류코드 구글시트(공통 오류코드 탭). HIRA(HR1000N) 본인인증+조회만 호출하므로\n*   공통 1000/1001/1010 체계만 매핑. GOVM 1500xxx(자동차/출입국/부동산 등)는 진료수집 무관이라 제외.","hangul_chars":67,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":81,"line_end":81,"block_type":"line","text":"* 성공/정상","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":83,"line_end":83,"block_type":"line","text":"* 입력값/조건","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"* 요청/세션","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":106,"line_end":106,"block_type":"line","text":"* 본인/간편인증","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"* 한도/혼잡 (IP 차단 포함)","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* 타임아웃","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"* 외부(기관/사이트)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"* 네트워크","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"* 조회 없음","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":125,"line_end":125,"block_type":"line","text":"* 미분류(사이트 직접 전달 오류메시지)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":127,"line_end":127,"block_type":"line","text":"* ---- prod 실측 현행화(2026-06-29) ----","hangul_chars":5,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"* 기관 응답이 정상적이지 않음(사이트 확인)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 우리측 타임아웃/ECONNRESET(공통 래퍼코드)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":132,"line_end":132,"block_type":"line","text":"* ---- hyphen (3-4): 업무코드(errMsg [코드]) + 통신코드(resCd). 형식이 겹치지 않아 한 맵 ----","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":135,"line_end":135,"block_type":"line","text":"업무코드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 보안문자 불일치 — prod 실측(2026-06-08) errMsg '[I0001-004] 보안문자가 일치하지 않습니다'","hangul_chars":22,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":144,"line_end":145,"block_type":"line","text":"* 메시지별 의미 갈림 — 실측 확정 필요(문서 155)\n* 동적 변형코드 — InfoTech 문서 미정의, prod 실측(2026-06-11)으로 분류","hangul_chars":33,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":146,"line_end":146,"block_type":"line","text":"* '처리중 오류가 발생하였습니다'","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* '인증번호가 올바르지 않습니다 (남은 횟수 n/3)'","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":148,"line_end":149,"block_type":"line","text":"* '네트워크 연결에 실패하였습니다'\n통신 resCd","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":159,"line_end":159,"block_type":"line","text":"* ---- prod 실측 현행화(2026-06-29) ----","hangul_chars":5,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":160,"line_end":162,"block_type":"line","text":"* timeout of 300000ms exceeded(공통 래퍼코드)\n* CF-99999: 어댑터가 업무코드 추출 실패 시 폴백. 실제 코드는 메시지에 [I0001-*]로 들어있음\n*  (예 [I0001-V01] 인증번호 오류 / [I0001-N01] 네트워크). 빈도 높음(30일 677건) → unwrap 점검 필요.","hangul_chars":56,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":166,"line_end":166,"block_type":"line","text":"* ---- inhouse (자체 스크래퍼 엔진): result.code = INH-* (엔진 result-codes.ts 미러) ----","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":174,"line_end":174,"block_type":"line","text":"* ---- prod 실측 현행화(2026-06-29) ----","hangul_chars":5,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/error/treat-error-vendor-map.ts","lang":"js","line_start":175,"line_end":175,"block_type":"line","text":"* 엔진 504/통신 타임아웃(공통 래퍼코드)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.entity.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* CF-QUEUE(전 공급자 만석 → 대기열 진입). 실패 아님","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.repository.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 분석로그 노이즈 제외 (항상): 자동차(CAT002) 수집 + 만석대기(CF-QUEUE) 로그 숨김","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.repository.ts","lang":"js","line_start":205,"line_end":205,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 분석로그 엑셀 다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"* 1차 인증 로그 적재 (B2C)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":98,"line_end":98,"block_type":"line","text":"* 만석 → 대기열 진입. 실패 아님","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"* 2차 인증 로그 적재 (B2C 진료정보 수집)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":156,"line_end":156,"block_type":"line","text":"loginType 2: 문자 인증","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"기타 간편인증은 패스로 처리","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log-b2c/log-b2c-treat.service.ts","lang":"js","line_start":175,"line_end":175,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.dto.ts","lang":"js","line_start":86,"line_end":86,"block_type":"line","text":"* 1차 인증 라우팅 공급자 (멀티 디스패처). 인증실패도 벤더 귀속용, 내부 세팅값.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.entity.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"* (예약) 내가먹는약 별도수집 활성화 전까지 미emit","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.entity.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* CF-QUEUE(전 공급자 만석 → 대기열 진입). 실패 아님","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":61,"line_end":65,"block_type":"jsdoc","text":"엑셀 전체다운로드용 keyset 배치 조회 (log_treat 30만+ 행 대응).\n - ltrId DESC 고정 + ltrId < lastLtrId 로 다음 배치 → OFFSET 없이 일정 속도.\n - 배치로 흘려 스트리밍 → 응답 즉시 시작(게이트웨이 타임아웃 회피)·메모리 일정.","hangul_chars":61,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":122,"line_end":122,"block_type":"line","text":"* 같은 로그인이 여러 기업에 활성 공존 → agc_id까지 맞춰 그 기업 회원 1명만(중복 제거). null-safe.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":143,"line_end":144,"block_type":"line","text":"* 영업대리점 필터(sagId/sacCode)가 있을 때만 조인. 없으면 log_treat 단독 카운트.\n*   기존엔 항상 4개 조인을 걸어 12만행 카운트가 ~1.5s 걸리던 페이지 병목 → 조인 제거로 수십 ms.","hangul_chars":54,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"* 분석로그 노이즈 제외 (항상): 자동차(CAT002) 수집 + 만석대기(CF-QUEUE) 로그 숨김","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":279,"line_end":279,"block_type":"line","text":"* log_treat에 agc_id 컬럼이 있어 조인 없이 직접 필터 → 카운트 조인 제거 가능","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":314,"line_end":314,"block_type":"line","text":"* 처리업체(1차 라우팅 공급자) 필터","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.repository.ts","lang":"js","line_start":332,"line_end":332,"block_type":"line","text":"* 영업대리점 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 분석목록 엑셀 다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":50,"line_end":51,"block_type":"line","text":"* 전체다운로드: log_treat 30만+ 행을 한 번에 받으면 게이트웨이 타임아웃에 끊긴다.\n*   ltrId keyset 배치로 끊어 엑셀 스트림에 즉시 흘려보낸다 → 응답 즉시 시작·메모리 일정.","hangul_chars":57,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"* 1차 인증 로그 적재","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":102,"line_end":102,"block_type":"line","text":"* 로그 적재용 데이터 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"* 1차 인증 라우팅된 공급자 (멀티 디스패처). 인증실패도 벤더별로 보이게 기록.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 만석 → 대기열 진입. 실패 아님","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"* 2차 인증 로그 적재","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":147,"line_end":147,"block_type":"line","text":"* 로그 적재용 데이터 조회","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":159,"line_end":160,"block_type":"line","text":"* 2차 로그도 주문의 분석번호로 연결 — 자체엔진은 2차 응답에 transactionId가 없어\n*  비워두면 주문↔로그 매칭이 깨져 모니터 주요에러(주문 기준)에서 사유가 'AUTO'로 뭉친다.","hangul_chars":59,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":167,"line_end":168,"block_type":"line","text":"* 2차 자료수집 라우팅 공급자 — jti(1차 성공 시 디스패처가 태깅)에서 복원.\n*   단일모드면 null → 미기록(기존 동작과 동일). 멀티 분산 시 2차 로그에도 벤더 귀속.","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":185,"line_end":185,"block_type":"line","text":"* 2차 수집 소요/타임아웃(벤더 측정) — 분할 효과·오래걸린 실패 집계용. 미측정 벤더는 null/0.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/log/log-treat.service.ts","lang":"js","line_start":230,"line_end":230,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":12,"line_end":12,"block_type":"line","text":"* 진료 처리 실시간 모니터링 — 업체별(에러 포함) + 단계별 에러 + 판단.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":25,"line_end":25,"block_type":"line","text":"* 코드 → 라벨 사전. 실제 prod 로그 기반. 모르는 코드는 라벨 대신 코드 그대로(프론트가 원문 문구 표시).","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 유저 입력","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"* 외부(쿠콘/기관) 장애","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"* 디스패처 내부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":58,"line_end":59,"block_type":"line","text":"* ★휴먼에러(유저실패) 판정 — 실패 중 '유저가 고쳐야 하는 입력/조건 오류'.\n*  나머지(기관·통신·시스템·시간초과·미상)는 시스템에러. 기존 VENDOR_MAP 카테고리 재사용.","hangul_chars":58,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 정보 오입력","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"* SMS 인증번호 오류","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* 인증 앱 미설치/미발급","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 인증서 문제","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* 연령 제한","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":80,"line_end":80,"block_type":"line","text":"* 미등록 코드는 코드 그대로(틀린 라벨로 뭉개지 않음)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":83,"line_end":85,"block_type":"line","text":"* 화면 라벨: 업체가 실제 내려준 메시지(codef_result_message)를 최우선으로 보여준다.\n*  메시지가 비면 기존 코드 라벨(failLabel)로만 폴백 — 임의 메시지를 지어내지 않아야\n*  나중에 코드로 원인 추적이 가능하다.","hangul_chars":69,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":95,"line_end":97,"block_type":"line","text":"* ★운영 부담 방어: overview는 무거운 다중 쿼리(log_treat 수회 스캔 등)라 매 폴링마다 돌리면 부하가 크다.\n*  결과를 짧은 TTL로 캐시하고, 동시 요청은 single-flight로 1계산만 공유한다.\n*  → 관리자/탭이 아무리 많이 폴링해도 실제 DB 계산은 TTL당 최대 1회로 상한(부담 상수화).","hangul_chars":87,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":101,"line_end":101,"block_type":"line","text":"* 월 집계 캐시(월별) — 853ms급 쿼리라 반복 클릭 시 재조회 방지. 과거 달은 불변, 이번 달도 60초면 충분.","hangul_chars":35,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* 신선한 캐시 → DB 안 침","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 계산 진행중이면 그 결과 공유(중복계산 방지)","hangul_chars":18,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* 레디스 장애로 모니터 전체가 500 나지 않도록 가드 — 실패 시 대기열 지표만 0","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 처리율(분당 속도)은 최근 WIN분, 파이프라인 퍼널(완료/실패)은 진행단계 backlog와 동일 24시간 기준","hangul_chars":34,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"* 전체 공급자","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":164,"line_end":169,"block_type":"line","text":"* 공급자별 성공/실패 (order_detail, 60분)\n* fail = 인증실패(ODD004) + 분석실패(ODD007) + 자료수집실패(ODD008). raw odd_state 또는 스케줄러가\n*  박은 odd_final_state(ODD004/ODD007) 어느쪽이든 실패로 집계.\n* ★시간기준을 처리시점(완료=odd_completed_at / 실패=odd_failed_at)으로 통일 — trend(그래프)·throughput과\n*  동일 기준. odd_updated_at으로 잡으면 (a)탈주 자동실패의 updated_at만 갱신돼 카드↔그래프 개수가 어긋나고\n*  (b)06:10 원본삭제 배치 UPDATE가 카드에 가짜로 섞인다. 처리시점 기준이면 카드=그래프=throughput 정합.","hangul_chars":126,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":180,"line_end":183,"block_type":"line","text":"* ★실패 3분류(통일) — 이탈 / 유저실패(휴먼에러) / 시스템실패. 모든 영역(업체별·funnel·처리추이·월)이 동일 정의 공유.\n*   이탈 = 2차 수집(CRS002) 미시도(SMS 미입력). 제출(2차 있음) 후 실패는 마지막 2차 실패코드 카테고리로 분기 —\n*   유저 입력/조건 오류(인증번호·정보·인증서·앱·연령) → 유저실패, 그외(기관·통신·시스템·시간초과 등) → 시스템실패.\n*   창은 지표별로: funnel=생성(created 24h), 업체별=처리(failed 60분), 처리추이=처리(failed 12h). LATERAL 1회로 마지막코드.","hangul_chars":145,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"* funnel — 생성 코호트(24h / 그중 60분)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"* 업체별 — 처리 60분(provStat.fail과 동일 창 → 이탈+유저+시스템 = 실패)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":235,"line_end":235,"block_type":"line","text":"* 처리추이 — 처리 12시간(시간대별)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"* (평균/최대 수집소요·타임아웃 지표는 운영에서 잘 안 봐 제거 — log_treat 스캔도 1개 감소)","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":246,"line_end":253,"block_type":"line","text":"* 공급자별 주요에러 — ★주문(order) 최종 실패 기준. provStat의 fail과 '동일 WHERE'라 Σ에러 = 실패 수(정합).\n*  각 실패 주문의 사유 = 그 주문의 마지막 2차 실패 로그코드(odd_transaction_id 매칭),\n*  로그가 없으면(탈주·자동실패) 상태로 합성: 인증단계(ODD001/003) → AUTO-INCOMPLETE(인증 미완료),\n*  수집단계(ODD002/005) → AUTO-COLLECT-FAIL(자료수집 미완료). 호출 단위로 세던 기존 방식은\n*  재시도·탈주 때문에 실패 수와 어긋났다(주문 19 vs 에러합 12). 주문 기준으로 통일해 일치시킨다.\n* ★성능(2026-07-08): 기존엔 실패주문 N건마다 code/msg/stage를 각각 상관 서브쿼리로 뽑아 log_treat를\n*  3N번 스캔 → 대량이면 200초+로 stg 커넥션을 고갈시켜 전체 마비. 같은 '마지막 2차실패 로그' 한 행에서\n*  세 값이 나오므로 LATERAL JOIN 1개로 합쳐 3N→N. 결과·정합(주문기준 Σ에러=실패수)은 그대로.","hangul_chars":224,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":293,"line_end":293,"block_type":"line","text":"* 분당 rate-limit: 허용건수(=maxFlows 공식) vs 최근 60초 실호출 — 벤 근접도","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":298,"line_end":298,"block_type":"line","text":"* 주요에러는 이미 주문 최종 실패 기준(provErrRows)이라 Σ = 실패 수. 별도 합성 불필요.","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":313,"line_end":313,"block_type":"line","text":"* 분당 rate-limit(타임) — limitPerMin/flowCost로 산출한 분당 허용건수 vs 최근 60초 실호출","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"* 실패 3분류(처리 60분) — 이탈(2차 미시도)/유저실패(휴먼). 시스템실패=fail-dropout-userFail(프론트).","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":334,"line_end":335,"block_type":"line","text":"* 현재 살아있는 단계별 적체 + 정체(stuck) — \"지금 어디에 몇 개가 쌓여 멈춰있나\"\n*   final_state IS NULL = 분석상태 스케줄러가 아직 정리 안 한 진짜 진행중 건","hangul_chars":48,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":343,"line_end":344,"block_type":"line","text":"* 진행건 = 최근 24시간 내 생성 + 미종결. 분석은 수분이면 끝나므로 24h면 실제 진행건은 다 잡힌다.\n*   (24h 넘게 미종결인 건은 처리 흐름이 아니라 '장기 미종결'로, 실시간 파이프라인에서 제외 — 정리는 별도)","hangul_chars":74,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":365,"line_end":368,"block_type":"line","text":"* 최근 12시간 시간대별 처리량 추이 — 빈 시간도 0으로 채워 연속 축 (재귀 CTE로 매 시각 생성)\n*   처리량은 실제 처리시점(완료=odd_completed_at / 실패=odd_failed_at) 기준으로 집계한다.\n*   odd_updated_at으로 하면 매일 ~06:10 도는 '30일 경과 원본데이터 삭제' 배치가\n*   30일 전자 완료/실패건(~1,700건)을 일괄 UPDATE → 6시에 가짜 처리량 폭증으로 찍힌다.","hangul_chars":101,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":397,"line_end":397,"block_type":"line","text":"* 그 시간대 실패 3분류(스택): 이탈(SMS 미입력) / 유저실패(휴먼) / 시스템실패","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":403,"line_end":403,"block_type":"line","text":"* 단계별 에러 (전체, log_treat 30분)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":415,"line_end":415,"block_type":"line","text":"* 코드별 업체 실제 메시지 보관(라벨용)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":431,"line_end":431,"block_type":"line","text":"* 시나리오(인증방식)별 성공률 — 2차 자료수집 기준 (방식별 문제 식별: 패스 등)","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":453,"line_end":457,"block_type":"line","text":"* ★보유(주문) 단위 이탈/실패 funnel — '생성 코호트가 어디서 끝났나'를 주문(odd) 단위로 집계.\n*  (기존 cert1 dropout=1차성공−2차로그 벤더별 뺄셈은 재시도·벤더 교차 라우팅으로 왜곡 → 폐기)\n*  tn_order_detail(odd_created_at 인덱스) 한 번 스캔(24h≈수백건, 가벼움). 60분/24시간 두 창을 한 쿼리로.\n*    완주율 = 종결건(진행중 제외) 중 완료 비율. 인증이탈 = ODD004(대부분 SMS 미입력).\n* 생성 코호트 요청/완료/진행중(주문 상태) — tn_order_detail 인덱스 한 스캔. 실패 분류는 위 failClsRows.","hangul_chars":137,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":479,"line_end":479,"block_type":"line","text":"* 이탈(SMS 미입력, 2차 미시도)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":480,"line_end":480,"block_type":"line","text":"* 유저실패(휴먼에러 — 인증번호/정보 오입력·인증서·앱·연령)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":481,"line_end":481,"block_type":"line","text":"* 시스템실패(기관·통신·시스템·시간초과 등)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":482,"line_end":482,"block_type":"line","text":"* 아직 진행중(미종결)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":495,"line_end":497,"block_type":"line","text":"* 1차 인증 벤더별 성패 (log_treat 기준, 60분) — order_detail 없는 인증실패도 벤더 귀속.\n*  ★rate(성공률)는 CF-03002(SMS 발송 도달) 기준이라 거의 100%가 된다 — '발송 성공'이지 '인증 완주'가\n*  아니기 때문. 실제 완주/이탈은 위 holdingFunnel(주문 단위)에서 정확히 본다(벤더별 뺄셈은 왜곡되어 제거).","hangul_chars":86,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":558,"line_end":558,"block_type":"line","text":"* 파이프라인 퍼널용 — 진행단계 backlog와 동일한 24시간 기준","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":585,"line_end":587,"block_type":"line","text":"* ★월 단위 집계 — '이번 달/8월 성공·이탈·실패 숫자'. 온디맨드(실시간 폴링·캐시와 분리)라\n*  15초 폴링에 부담을 주지 않는다. 한 달 order_detail 범위스캔(odd_created_at 인덱스)\n*  + 실패 분류(EXISTS idx_odd_tx). 관리자가 월 선택 시 1회만 조회.","hangul_chars":69,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":590,"line_end":590,"block_type":"line","text":"* month = 'YYYY-MM'. 형식 안 맞으면 이번 달로.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":596,"line_end":596,"block_type":"line","text":"* 반복 클릭 → DB 안 침","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":600,"line_end":600,"block_type":"line","text":"* 주문상태 per-provider(요청/완료/진행중) — odd_provider(1차 배정 벤더) 기준.","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":615,"line_end":615,"block_type":"line","text":"* 실패 3분류(이탈/유저실패/시스템실패) — 마지막 2차 실패코드 카테고리로. 월 온디맨드(캐시)라 행 페치+TS 집계.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":648,"line_end":648,"block_type":"line","text":"* per-provider 결합 (요청/완료/진행중 + 이탈/유저/시스템)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":682,"line_end":682,"block_type":"line","text":"* 이탈(SMS 미입력)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":683,"line_end":683,"block_type":"line","text":"* 유저실패(휴먼에러)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":684,"line_end":684,"block_type":"line","text":"* 시스템실패","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":689,"line_end":689,"block_type":"line","text":"* 벤더별 분해","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":692,"line_end":692,"block_type":"line","text":"* 캐시 무한증식 방지 — 24개월 넘으면 가장 오래된 것 제거","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":707,"line_end":712,"block_type":"line","text":"* ★일별 총합계 — [from,to] 기간을 일자별로. '시도 기준'(발생 종결건) + '고객 기준'(최초 종결 시도일 코호트 회복).\n*  실시간 폴링·캐시와 분리된 온디맨드(기간 범위스캔). 분류 정의(진짜이탈/유저실패/시스템실패)는\n*  overview·monthly와 완전히 동일(isHumanError 재사용) — 세 화면 숫자가 어긋나지 않게. 벤더 통합(전체).\n*  ⚠ cliId(고객사 필터)는 tn_order_detail에 cli 링크가 없어(별도 tn_client_order_detail) 후속 — 식별기준 확정 후 추가.\n* ★부하방어 3겹 — 관리자가 새로고침을 아무리 눌러도 실제 DB 계산은 (키·TTL)당 1회로 상한.\n*   ① TTL 캐시  ② single-flight(동시 동일요청 1계산 공유)  ③ 과거 구간 장기 TTL + 범위 상한(92일).","hangul_chars":182,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":715,"line_end":715,"block_type":"line","text":"* 오늘 포함 범위(값이 변할 수 있음)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":716,"line_end":716,"block_type":"line","text":"* 과거(불변) 범위 — 10분 캐시","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":717,"line_end":717,"block_type":"line","text":"* 한 번에 스캔할 최대 기간(무거운 전체스캔 차단)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":729,"line_end":729,"block_type":"line","text":"* 기본: 최근 15일(오늘 포함). 형식 안 맞으면 기본으로.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":736,"line_end":736,"block_type":"line","text":"* 뒤집힘 방어","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":737,"line_end":738,"block_type":"line","text":"* 미래 조회 방지\n* 범위 상한 — from을 당겨 최대 스팬으로 클램프(무거운 전체 스캔 차단)","hangul_chars":31,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":748,"line_end":748,"block_type":"line","text":"* 상품(기업상품) 다중필터 — 빈값·중복 제거·정렬·개수 상한(IN 리스트 방어). 미선택이면 전체 통합.","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":756,"line_end":756,"block_type":"line","text":"* 과거(불변) 범위면 장기 TTL, 오늘 포함이면 단기. 신선 캐시는 DB 안 침.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":760,"line_end":760,"block_type":"line","text":"* single-flight — 같은 키 계산이 진행중이면 새 쿼리 안 날리고 그 결과를 공유.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":766,"line_end":766,"block_type":"line","text":"* 캐시 무한증식 방지 — 48개 넘으면 가장 오래된 것 제거","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":788,"line_end":788,"block_type":"line","text":"* 버킷 키 — 일: YYYY-MM-DD, 월: YYYY-MM, 벤더: odd_provider. 시도·코호트 둘 다 같은 키로 묶는다.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":796,"line_end":796,"block_type":"line","text":"* 기업상품 다중필터 — 선택 시에만 tn_order 조인(PRD003=기업상품) + 상품코드 IN. 미선택이면 조인 없이 전체 통합.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":807,"line_end":810,"block_type":"line","text":"* ★성능: 종결주문 '전부'에 상관 서브쿼리(EXISTS+LATERAL)를 돌리면 대량 구간에서 게이트웨이 타임아웃.\n*  성공 주문은 서브쿼리 불필요(요청/성공 카운트·코호트는 성공여부만 필요) → 서브쿼리는 '실패 주문'에만.\n*  A(전체 종결, 서브쿼리 없이 범위스캔): 요청/성공 + 코호트.  B(실패만 + LATERAL): 실패 3분류.\n*  to는 그날 끝까지 포함(< to+1일). createdAt은 문자열로 받아 코호트 정렬을 드라이버 Date 파싱에 의존하지 않게.","hangul_chars":138,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":849,"line_end":849,"block_type":"line","text":"* 시도 기준(요청/성공) + 코호트용 고객별 이력 — A(서브쿼리 없는 전체 종결).","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":869,"line_end":869,"block_type":"line","text":"* 실패 3분류 — B(실패만). 진짜이탈(2차 미시도)/유저실패(휴먼)/시스템실패(그외). 요청=성공+이탈+유저+시스템 정합.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":877,"line_end":877,"block_type":"line","text":"* 고객 기준 — 각 고객을 '기간 내 최초 종결 시도일'에 한 번만 귀속. 최초성공/최초실패, 최초실패는 이후 성공 시 회복.","hangul_chars":44,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":888,"line_end":888,"block_type":"line","text":"* 최초실패 후 이후 종결 성공 → 회복","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":893,"line_end":893,"block_type":"line","text":"* 연속 축(빈 버킷도 0)으로 행 구성 — 일 단위=매일, 월 단위=매월.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":898,"line_end":898,"block_type":"line","text":"* 나타난 벤더만, 선호 순서로. 라벨은 tn_treat_provider 한글명.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":935,"line_end":935,"block_type":"line","text":"* 진짜이탈","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":943,"line_end":943,"block_type":"line","text":"* 중복제외 고객","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":946,"line_end":946,"block_type":"line","text":"* 최초실패(회복대상)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":947,"line_end":947,"block_type":"line","text":"* 회복성공","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":950,"line_end":950,"block_type":"line","text":"* 최종성공 = 최초성공 + 회복성공","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":956,"line_end":956,"block_type":"line","text":"* 합계 — 코호트는 고객을 최초일에 1회만 귀속하므로 일자 합 = 기간 합(정합). 비율만 합에서 재산출.","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":979,"line_end":979,"block_type":"line","text":"* 기업상품(PRD003) 목록 — 일별 집계 다중필터 셀렉트 채우기용. 목록은 잘 안 변해 5분 캐시.","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1004,"line_end":1004,"block_type":"line","text":"* 진료집계 스타일 엑셀 — 원본 리포트 레이아웃(제목·기간·그룹헤더 병합·% 서식·색·테두리·틀고정) 재현.","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1032,"line_end":1032,"block_type":"line","text":"* 헤더 5행 + 일자열 고정","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1047,"line_end":1047,"block_type":"line","text":"* 기간/대상","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1054,"line_end":1054,"block_type":"line","text":"* 그룹헤더(4행) + 컬럼명(5행)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1081,"line_end":1081,"block_type":"line","text":"* 데이터 + 합계","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1083,"line_end":1083,"block_type":"line","text":"* 긍정 비율만 색(좋음/주의/나쁨)","hangul_chars":12,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1115,"line_end":1115,"block_type":"line","text":"* 주의사항","hangul_chars":4,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1137,"line_end":1139,"block_type":"line","text":"* 벤더별 에러 카탈로그.\n*  - vendors: 우리가 아는 에러 전부(VENDOR_MAP 사전, OK 제외)를 벤더별로 깔고, 각 코드에 최근 N일 발생건수·발생률(벤더 전체 시도 대비) 부착. 발생 0인 코드도 함께 노출.\n*  - unmapped: 사전에 없는데 실제로 뜬 코드(의미 미상)만 따로 모아 맨 아래 한 표로.","hangul_chars":90,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1145,"line_end":1145,"block_type":"line","text":"* 코드별 실발생 (벤더 × 코드, 상태 무관 — 그 코드가 찍힌 횟수)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1156,"line_end":1156,"block_type":"line","text":"* 벤더 전체 시도 (발생률 분모)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1168,"line_end":1168,"block_type":"line","text":"* codef 계약종료 → 제외. inhouse(자체엔진)는 운영 주력이라 포함.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1172,"line_end":1172,"block_type":"line","text":"* 사전 전체를 벤더별로 — OK 코드는 제외(에러 카탈로그)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1203,"line_end":1203,"block_type":"line","text":"* 미분류 — 실발생했지만 사전에 없는 코드만(대기열·자동차 정상 제외)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1208,"line_end":1208,"block_type":"line","text":"* codef 계약종료 → 제외","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1210,"line_end":1210,"block_type":"line","text":"* 사전 등록됨","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/monitor/treat-monitor.service.ts","lang":"js","line_start":1212,"line_end":1212,"block_type":"line","text":"* 실패(CRT002)로 찍힌 적 없으면 정상/추가인증 — 에러 아님","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.dto.ts","lang":"js","line_start":13,"line_end":13,"block_type":"line","text":"* 관리자 — 자동차보험 수집 전체 ON/OFF (전역 설정). 운영 중 즉시 차단/복구.","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.dto.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 관리자 — 공급자 설정 수정 (부분 수정, tpr_key 는 경로파라미터)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.module.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 진료 공급자 설정 — 관리자 CRUD + 디스패처 풀 소스(DB). DrizzleService 는 글로벌.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":12,"line_end":13,"block_type":"line","text":"* 사용중(enabled)인 공급자만 — 디스패처 풀 소스. 정렬: tprSort 우선, 동점이면 단가 오름차순.\n*   라우팅 우선순위 = tprSort(관리자가 순서변경). 단가는 동순위 tiebreaker로만.","hangul_chars":52,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 관리자 목록 — 전체(비활성 포함). tprSort 우선(=라우팅 우선순위 순), 동점이면 단가 오름차순.","hangul_chars":32,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"* 관리자 수정 (단가/한도/사용여부 등) — tpr_key 기준","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* 처리업체 기록 — 진료 처리완료 시 주문상세에 공급자 저장","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":53,"line_end":53,"block_type":"line","text":"* 공급자 수집 분할 횟수. 미설정/이상치는 1(분할 없음)로 안전 폴백.","hangul_chars":25,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 진료 전역 설정 조회(key) — 없으면 null","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.repository.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"* 진료 전역 설정 upsert(key=value)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":7,"line_end":7,"block_type":"line","text":"* 디스패처가 쓰는 풀 항목 (configuration.treatPool 과 동일 형태)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":13,"line_end":13,"block_type":"line","text":"* 라우팅 우선순위(낮을수록 먼저). 단가는 동순위 tiebreaker.","hangul_chars":19,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":14,"line_end":14,"block_type":"line","text":"* 분당 rate-limit(타임) 적용 여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":17,"line_end":17,"block_type":"line","text":"* DB 조회 캐시 — 단가 변경이 ~15초 내 반영, 매 요청 DB조회 방지","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":18,"line_end":18,"block_type":"line","text":"* tn_treat_setting 전역 자동차 수집 ON/OFF 키","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* 자체엔진 전용, 기본 OFF","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"* tn_treat_setting 모니터링 알림 웹훅 URL (빈 값=비활성)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* 발송할 알림 종류(JSON 배열)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":22,"line_end":22,"block_type":"line","text":"* 발송 중복억제용 상태(JSON {경고키: 발송시각ms})","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 모니터링 알림 종류 — 모니터 경고(warnings)의 type과 1:1. 어드민 체크박스로 켜고 끔.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":35,"line_end":40,"block_type":"jsdoc","text":"진료 공급자 설정 서비스.\n- getPool(): 디스패처용 풀(enabled, 단가오름차순). DB→캐시, DB 비었거나 장애 시 env(treatPool) 폴백.\n- 관리자 CRUD: list / update (수정 시 캐시 무효화 → 즉시 반영).\n- recordProvider(): 진료 처리완료 시 주문상세에 처리업체 기록.","hangul_chars":66,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"* 디스패처 풀 — DB 우선, 캐시, 폴백(env)","hangul_chars":11,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"* env 폴백은 sort 미지정 → 0 동점 → 단가순","hangul_chars":11,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"* env 폴백은 기본 미적용","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"* 관리자 — 전체 목록","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"* 관리자 — 설정 수정 (캐시 무효화)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":105,"line_end":108,"block_type":"line","text":"* 자동차보험 수집 전역 ON/OFF — DB(tn_treat_setting) 우선, 15초 캐시, 미설정/장애 시 env(enableTreatCar) 폴백.\n*   운영 중 어드민 토글로 즉시(캐시TTL 내) 전 벤더 자동차 수집 차단/복구.\n* 캐시 없이 매번 DB 조회 — 진료조회당 1~2회뿐이라 부하 미미하고, 토글이 즉시 반영돼야 안전.\n*   (캐시 두면 OFF 후에도 stale ON이 남아 자동차가 계속 나가는 문제가 있었음)","hangul_chars":107,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"* 자동차보험 수집 전역 토글 설정 (어드민). 캐시 무효화 → 즉시 반영.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"* 자동차 전역 설정 조회(어드민 화면 표시용)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 자동차 범위 정책. enable_treat_car가 master kill이며 DB 장애도 전체 자동차를 차단한다.","hangul_chars":23,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"* master와 카나리를 모두 켠 경우에만 검증된 공급자의 자동차를 허용한다.","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"* 모니터링 알림 웹훅 설정 조회 — URL + 발송할 종류 (미설정/장애 시 기본값)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":175,"line_end":175,"block_type":"block","text":"깨진 JSON → 기본값","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":185,"line_end":185,"block_type":"line","text":"* 모니터링 알림 웹훅 설정 (URL 빈 값=비활성, types=발송할 종류)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":194,"line_end":194,"block_type":"line","text":"* 알림 발송 중복억제 상태 조회/저장 (TreatAlertService 전용)","hangul_chars":16,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/provider/treat-provider.service.ts","lang":"js","line_start":210,"line_end":210,"block_type":"line","text":"* 처리업체 기록 (실패해도 본 플로우엔 영향 없게 swallow)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 같은 경고 30분 중복억제(스팸 방지)","hangul_chars":13,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":10,"line_end":16,"block_type":"jsdoc","text":"진료 모니터링 알림 발송 — 모니터 경고(overview.warnings)를 채널로 푸시.\n - provider(공급자 장애) 경고: 그 벤더 전용 URL(tn_treat_provider.tprWebhookUrl)이 있으면 그 채널로.\n   → \"벤더에게 자기 장애를 통보\"(옥토버/쿠콘/자체엔진 등). 없으면 전역으로 폴백.\n - 그 외 경고(성공률/대기열/정체/정합성/시나리오): 전역 URL(monitor_webhook_url)로, 어드민이 켠 종류만.\n 신규 경고는 30분 1회, 사라지면 복구 1회. 스케줄러(analysis-status, 5분)가 checkAndSend()를 호출한다.","hangul_chars":126,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"* 전역 채널(url/types)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 벤더 전용 채널: tprKey → tprWebhookUrl (설정된 것만)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 채널 하나도 없음 = 알림 끔","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":50,"line_end":50,"block_type":"line","text":"* 대상 채널: provider 경고 & 그 벤더 전용 URL 있으면 벤더 채널, 아니면 전역(어드민이 켠 종류만)","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"* 채널별 dedup(같은 문구라도 채널 다르면 별도)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 직전엔 떴다가 이번엔 사라진 경고 → 복구 알림 1회(같은 채널) + 상태 제거","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-alert.service.ts","lang":"js","line_start":87,"line_end":87,"block_type":"line","text":"* 구글챗/슬랙 호환 incoming webhook 포맷 = { text }. 발송 실패는 swallow(모니터/스케줄러 영향 없게).","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-car-canary.service.ts","lang":"js","line_start":23,"line_end":24,"block_type":"line","text":"* master+자동차 카나리가 모두 ON인 허용 공급자만 전역 3석을 예약한다.\n* Redis 장애/만석이면 건강만 진행한다.","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":8,"line_end":8,"block_type":"jsdoc","text":"프론트 sendBeacon 페이로드 — 인증단계 이탈 시점. 전부 optional(best-effort).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"★엔진 세션 상관키(B) — jti에 engine sessionId 인코딩. 있으면 엔진 대시보드로 포워드.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":19,"line_end":22,"block_type":"jsdoc","text":"인증 이탈 클라 비콘 적재. 서버 퍼널(엔진)이 못 보는 '유저가 언제·어디서 떠났나'를 클라 시점으로 채운다.\nbest-effort — 적재 실패가 응답을 막지 않게 삼킨다(비콘은 이미 유저가 떠난 뒤라 재시도 의미 없음).","hangul_chars":75,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 구조화 로그 — CloudWatch/저널서 즉시 이탈패턴 grep 가능('감 잡기'의 1차 수단).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":56,"line_end":57,"block_type":"line","text":"* ★B: jti에서 engine sessionId 복원 → 엔진 대시보드로 포워드해 그 세션 타임라인에 '클라 이탈' 찍기.\n*   jti 없으면(certify_wait 등 인증 전) 스킵. best-effort — 실패해도 tn_treat_dropout엔 이미 있음.","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat-dropout.service.ts","lang":"js","line_start":59,"line_end":61,"block_type":"line","text":"* ★프론트 jti는 디스패처 라우팅 봉투 {p,j,r}(멀티 벤더) 또는 raw 벤더 jti(단일 모드).\n*   inhouse로 라우팅됐을 때만 안쪽 jti(tag.j)로 engine sessionId 복원. decodeTag=null=단일모드면 jti 그대로.\n*   (2026-07-01 버그: 봉투째 decodeInhouseSession해서 sessionId 못 찾았음 → decodeTag로 한 겹 깜)","hangul_chars":61,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 인증 이탈 비콘 (프론트 sendBeacon). 인증가드 없음(유저 세션 비콘). best-effort — 항상 200.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":46,"line_end":46,"block_type":"line","text":"* 대기열 순번 폴링(=하트비트). 클라가 주기적으로 호출. READY면 certify 재요청.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"* 대기열 이탈 (창 닫기 등). best-effort.","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":69,"line_end":69,"block_type":"line","text":"★폰/IP 레이트리밋(RATE_LIMIT_CERTIFY_PER_MIN>0 일 때만). 신원 살포 남용 차단","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":93,"line_end":94,"block_type":"line","text":"고객의 분석\n실패후 고객 혹은 FC의 재분석","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.controller.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"* 진료정보 요청 및 분석까지 같이 진행(백그라운드에서 진행)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.dto.ts","lang":"js","line_start":90,"line_end":90,"block_type":"jsdoc","text":"인증상세구분","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.dto.ts","lang":"js","line_start":165,"line_end":165,"block_type":"line","text":"* [1단계] 대기열 재요청 시 기존 큐 ID — 만석이어도 순번 유지(맨뒤 추락 방지). 멀티 디스패처만 사용.","hangul_chars":36,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.dto.ts","lang":"js","line_start":172,"line_end":172,"block_type":"line","text":"* 심평원인증요청후 진료내역 요청 시 추가 항목","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.dto.ts","lang":"js","line_start":301,"line_end":301,"block_type":"line","text":"* 심평원인증요청후 진료내역 요청 시 추가 항목","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.dto.ts","lang":"js","line_start":425,"line_end":425,"block_type":"line","text":"* 대기열 진입(multi 만석) 시에만 채워짐 — 이 값으로 순번 폴링 후 certify 재요청","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 진료내역 스크래핑 공급자 스위치 (configuration.treatProvider: 'codef'(기본)|'coocon')","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":76,"line_end":77,"block_type":"line","text":"* 자동차보험 진료 수집 ON/OFF는 TreatProviderService.isCarEnabled()로 일원화\n*   (DB tn_treat_setting 우선, env enableTreatCar 폴백). 운영 중 어드민 토글로 즉시 차단/복구.","hangul_chars":33,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":79,"line_end":82,"block_type":"jsdoc","text":"관리자 재분석 이벤트 (비동기 처리).\n자료수집은 건너뛰고 compare(분석)만 실행. 끝나면 요청한 관리자에게 알람 push.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":118,"line_end":120,"block_type":"jsdoc","text":"Codef 응답 코드(CF-*)를 B2C 내부 코드(BOD*)로 변환","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":124,"line_end":124,"block_type":"line","text":"분석완료","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"자료수집실패","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"분석실패","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":130,"line_end":130,"block_type":"line","text":"기타 에러 코드는 분석실패로 처리","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":135,"line_end":142,"block_type":"jsdoc","text":"자동차(2차) 로그 적재용 응답 구성\n다건 API는 배치 전체 공유 result 1세트만 반환하므로 자동차 개별 성공/실패를 result.code로 알 수 없다.\n자동차 로그가 기본(basic) 호출의 result로 위조되지 않도록, 자동차 데이터 수집 여부로 결과를 보정한다.\n- 공유 인증 실패(code !== CF-00000): 자동차도 동일 배치 사유로 실패 → 공유 result 그대로 사용\n- 공유 인증 성공 + 자동차 데이터 수집됨: 자동차 성공 → 공유 result(성공) 그대로 사용\n- 공유 인증 성공 + 자동차 데이터 미수집: 자동차 미수집 → 성공코드 대신 미수집 상태로 보정(로그 위조 방지)","hangul_chars":178,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":155,"line_end":156,"block_type":"line","text":"* 기본 인증은 성공했으나 자동차 진료정보가 수집되지 않은 경우(미수집)\n* 항목별 result 미제공으로 인한 합성 상태값 → 결과상태는 실패(미수집)로 적재","hangul_chars":57,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":181,"line_end":181,"block_type":"line","text":"민감상병표기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"동일계정으로 구분값이 필요할 경우 암호화 해서 넣기","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":193,"line_end":193,"block_type":"line","text":"* 2차 진료정보 요청시 필요값","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":194,"line_end":194,"block_type":"line","text":"보안문자 이미지정보(필수)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":195,"line_end":195,"block_type":"line","text":"보안문자 새로고침 \"0\": 기본, \"1\": 재요청, \"2\" : 입력취소(default:0)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":196,"line_end":196,"block_type":"line","text":"[SMS 인증]필수","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":197,"line_end":197,"block_type":"line","text":"! 추가확인필요 \"0\": cancel , \"1\": ok","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":198,"line_end":198,"block_type":"line","text":"인증후 요청일 시 true 고정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":207,"line_end":210,"block_type":"line","text":"* 2차 자료수집을 다건(배열)으로 발사 - 공유 twoWayInfo를 전 요소에 동일 적용 (index 0=기본, 1=자동차)\n* 자동차요소(index 1)는 원본 carData와 동일한 자동차 수집 파라미터(organization '0020'/type '1' 민감상병표기/id)를\n* 명시적으로 유지한다. 상품 구분자는 inquiryType만 사용하며, 다건전환으로 자동차 전용 파라미터가 누락되지 않도록 명시한다.\n* 자동차(inquiryType='1')는 자동차 수집 OFF면 제외 (기능 OFF, 코드 보존)","hangul_chars":123,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":221,"line_end":221,"block_type":"line","text":"공통값(원본 carData와 동일)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":222,"line_end":222,"block_type":"line","text":"민감상병표기(원본 carData와 동일)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":223,"line_end":223,"block_type":"line","text":"동일계정 구분값(원본 carData와 동일 소스)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":229,"line_end":230,"block_type":"line","text":"* 2차 진료조회 호출. 예외성 실패(타임아웃/네트워크/E0304 등)는 createTreatLog 적재 전에\n* 핸들러가 중단되어 로그가 통째로 누락되던 문제가 있었다(로그관리 미표시). 예외도 실패 로그를 남기고 실패 처리한다.","hangul_chars":74,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":240,"line_end":241,"block_type":"line","text":"* 벤더 거래번호(쿠콘 trSeq / 하이픈 reqCd)를 우선 기록. 없을 때만 세션태그(jti)로 폴백.\n*  (타임아웃·통신실패건의 CS 추적키 — 예전엔 jti 블롭이 저장돼 벤더 검색이 안 됐다.)","hangul_chars":57,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":243,"line_end":243,"block_type":"line","text":"* 수집 소요/타임아웃여부(벤더가 예외에 실어줌) — 분할 효과·오래걸린 실패 집계용.","hangul_chars":32,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":247,"line_end":247,"block_type":"line","text":"* 실패 로그 적재(2차 기본) — 운영 로그관리에서 추적 가능하도록","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":255,"line_end":256,"block_type":"line","text":"* 실패 상태 변경 + 예약수 환불 (errorTreat은 마지막에 throw하므로 흡수)\n*   상태는 errorTreat 내부에서 단계별 분기: 수집 타임아웃→분석실패(ODD007), 그 외→인증실패(ODD004).","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":271,"line_end":271,"block_type":"line","text":"* 예외성 실패는 위에서 로그/상태 처리 완료 → 이후 정상 분석 흐름 중단","hangul_chars":27,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":274,"line_end":276,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 신규 API 별도 호출 (task-01) — 다건과 별개, 실패해도 분석 플로우 유지\n* 입력은 옛 carData와 동일한 organization '0020' 세트(=treatItems[1]) 사용\n* [task-01 보류] CODEF_DRUG_URL 인프라 미설정 — 인프라 준비 후 아래 주석 해제 (현재 호출 비활성화, no-op)","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":278,"line_end":285,"block_type":"line","text":"const drugApiPromise = this.codefService\n  .fetchMedicineSummary(treatItems[1], dto.oddId)\n  .catch((e) => {\n    this.logger.error(\n      `내가 먹는약 한눈에 API 호출 실패 (정회원): oddId=${dto.oddId}, error=${e?.message || e}`,\n    );\n    return null;\n  });","hangul_chars":15,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":287,"line_end":289,"block_type":"line","text":"* index 0=기본, 1=자동차로 역다중화 (task-06 다건 결과)\n* 다건 API는 배치 전체에 대한 공유 result 1세트만 반환하므로(항목별 result 미제공)\n* 자동차 개별 성공/실패를 result.code로 구분할 수 없다. 자동차 포함 여부는 아래 data[1] 길이로만 판정(부분허용 정책).","hangul_chars":79,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":299,"line_end":299,"block_type":"line","text":"* 2차 인증(기본) 결과 로그 적재","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":306,"line_end":308,"block_type":"line","text":"* 2차 인증(자동차) 결과 로그 적재 — 자동차 수집 OFF(carEnabled=false)면 적재 생략.\n*   OFF면 treatItems에 자동차를 안 실어 실제 수집도 안 하지만, 이 로그 적재가 carEnabled와\n*   무관하면 CAT002(미수집) 슬롯이 남아 자동차가 나간 것처럼 보였다. 적재도 토글에 일원화.","hangul_chars":80,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":321,"line_end":322,"block_type":"line","text":"* idx0(기본) 실패 시 전체 실패 처리\noddId, orderDetail.member.memId, dto.usrName 추가필요","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":335,"line_end":335,"block_type":"line","text":"//*  임시데이터 저장","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":351,"line_end":351,"block_type":"line","text":"* 주문상세이력상태변경(인증확인에러) //자료수집에러","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":357,"line_end":357,"block_type":"line","text":"* 인증실패: 예약수 환불","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":365,"line_end":365,"block_type":"line","text":"자부상 기본, 상세 데이터 create 기능 추가(2025-03-10)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":370,"line_end":370,"block_type":"line","text":"* 부분허용 정책: 자동차 데이터 부재(미수집)는 정상 경로이므로 옵셔널/빈배열 기본값으로 안전 처리","hangul_chars":40,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":379,"line_end":379,"block_type":"line","text":"* 자동차는 내부 카나리 부가정보다. 저장 실패가 건강 진료 성공/주문 상태를 뒤집지 않는다.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":386,"line_end":388,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 응답 처리 — 실패하더라도 분석 플로우는 계속\n* result/data 필드가 비정상(undefined)이어도 동기 throw가 발생하지 않도록 try/catch + 옵셔널 체이닝 적용\n* 빈 리스트 응답에서도 createMedicineSummary를 호출해 기존 stale 데이터를 정리 (N→0 케이스 대응)","hangul_chars":82,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":409,"line_end":413,"block_type":"line","text":"* 바로 분석이 진행되 불필요한 스텝으로 보임\nawait this.orderDetailService.updateOrderDetail({\n  oddId: dto.oddId,\n  oddState: OrderDetailState.자료수집완료,\n});","hangul_chars":24,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":415,"line_end":416,"block_type":"line","text":"* 분석과 재분석의 상태변경이 달라야 하는지?\n* 주문상세이력상태변경(분석요청)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":419,"line_end":419,"block_type":"line","text":"분석요청","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":422,"line_end":423,"block_type":"line","text":"* 분석\n* 2025-03-12 기준 내부 로직에 자동차 진료기록 분석도 포함","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":429,"line_end":429,"block_type":"line","text":"* 주문상세이력상태변경(분석실패) - 상태 변경을 먼저 실행","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":449,"line_end":449,"block_type":"line","text":"* 분석실패: 예약수 환불","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":457,"line_end":457,"block_type":"line","text":"* Order 카운트 추가","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":460,"line_end":461,"block_type":"line","text":"* 임시데이터 삭제\nawait this.treatRepository.delete(oddId);","hangul_chars":7,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":463,"line_end":463,"block_type":"line","text":"* 분석성공시","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":471,"line_end":471,"block_type":"line","text":"* 주문상세이력상태변경(분석완료)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":480,"line_end":480,"block_type":"line","text":"* 처리 벤더 식별 (jti 태그의 provider; 단일·태그없음이면 codef)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":483,"line_end":484,"block_type":"line","text":"* 추후 2안으로 변경시 조건에 따라 알림 및 실패 처리 하지 않도록 조치 필요\n* 1안의 경우 해당 건도 바로 실패건으로 인지해서 알림을 보내야함","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":498,"line_end":502,"block_type":"line","text":"* 주문상세이력상태변경 — 2차 실패를 단계별로 분류 (이 경로는 분석 프로시저 전이라 '분석실패' 아님).\n*   진짜 분석실패(ODD007)는 createAnalyze catch에서만. 여기서는:\n*     - 인증 단계 실패(인증번호·인증서·미승인·앱미설치·만료·인증타임아웃·개인정보오류) → 인증실패(ODD004)\n*     - 그 외(수집 타임아웃·처리중/기관 오류·네트워크·시스템 등) → 자료수집실패(ODD008)\n*   수집 데이터가 없는 상태라, 둘 다 재분석 불가(가드가 막음). 수집 타임아웃은 oddTimeout=1로도 표시.","hangul_chars":154,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":524,"line_end":524,"block_type":"line","text":"* 인증실패: 예약수 환불 (ordId는 orderDetail에서 조회)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":539,"line_end":539,"block_type":"line","text":"* ⑤ filter에서 category·retryable 해석에 사용","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":543,"line_end":546,"block_type":"line","text":"* (vendor, native코드) → 알림톡 실패 메시지. 단일 출처는 resolveTreatError(error 모듈).\n*   codef 16코드는 기존 switch와 동일 메시지(resolver 36테스트가 보장).\n*   coocon·octover·hyphen native코드도 이제 category로 분류돼 generic default를 벗어남.\n*   CF-03002(2차)만 loginType 의존 특수 메시지라 여기서 분기 유지.","hangul_chars":64,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":559,"line_end":560,"block_type":"line","text":"* 수집 타임아웃(병력 과다 헤비유저)이면 기본 메시지 대신 건강이음 안내만 보낸다.\n*   다른 실패(인증/데이터없음 등)는 기존 메시지 유지.","hangul_chars":53,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":579,"line_end":579,"block_type":"line","text":"민감상병표기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":590,"line_end":590,"block_type":"line","text":"* 2차 진료정보 요청시 필요값","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":604,"line_end":605,"block_type":"line","text":"* B2C 2차는 certify 응답의 oddId(=bodId)를 1차 키로 써야 한다.\n* agcCode 최신 1건 재조회는 같은 기업 동시 요청에서 다른 고객 주문으로 교차 저장될 수 있다.","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":633,"line_end":637,"block_type":"line","text":"* 2차 자료수집을 다건(배열)으로 발사 - 공유 twoWayInfo를 전 요소에 동일 적용 (index 0=기본, 1=자동차)\n* 자동차요소(index 1)는 원본 carData와 동일한 자동차 수집 파라미터(organization '0020'/type '1' 민감상병표기/id)를\n* 명시적으로 유지한다. 상품 구분자는 inquiryType만 사용하며, 다건전환으로 자동차 전용 파라미터가 누락되지 않도록 명시한다.\n* 자동차(inquiryType='1')는 자동차 수집 OFF면 제외 (기능 OFF, 코드 보존)\n* B2C agcCode는 여러 사용자가 공유하므로 G0 1회 카나리에서 항상 제외한다.","hangul_chars":147,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":645,"line_end":645,"block_type":"line","text":"공통값(원본 carData와 동일)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":646,"line_end":646,"block_type":"line","text":"민감상병표기(원본 carData와 동일)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":647,"line_end":647,"block_type":"line","text":"B2C는 agcCode 사용(원본 carData와 동일 소스)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":655,"line_end":657,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 신규 API 별도 호출 (B2C, task-01) — 다건과 별개, 실패해도 분석 플로우 유지\n* 입력은 옛 carData와 동일한 organization '0020' 세트(=treatItems[1]) 사용\n* [task-01 보류] CODEF_DRUG_URL 인프라 미설정 — 인프라 준비 후 아래 주석 해제 (현재 호출 비활성화, no-op)","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":659,"line_end":666,"block_type":"line","text":"const drugApiPromise = this.codefService\n  .fetchMedicineSummary(treatItems[1], 0)\n  .catch((e) => {\n    this.logger.error(\n      `내가 먹는약 한눈에 API 호출 실패 (B2C): bodId=${bodId}, error=${e?.message || e}`,\n    );\n    return null;\n  });","hangul_chars":12,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":668,"line_end":670,"block_type":"line","text":"* index 0=기본, 1=자동차로 역다중화 (task-06 다건 결과)\n* 다건 API는 배치 전체에 대한 공유 result 1세트만 반환하므로(항목별 result 미제공)\n* 자동차 개별 성공/실패를 result.code로 구분할 수 없다. 자동차 포함 여부는 data[1] 존재로만 판정(부분허용 정책).","hangul_chars":77,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":680,"line_end":680,"block_type":"line","text":"* 2차 인증(기본) API 로그 적재","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":701,"line_end":701,"block_type":"line","text":"* Codef 응답 코드 검증 (정회원과 동일)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":707,"line_end":707,"block_type":"line","text":"* B2C order_detail 실패 상태 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":715,"line_end":715,"block_type":"line","text":"* B2C 분석 실패 시 알림톡 발송","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":738,"line_end":738,"block_type":"line","text":"* 2차 인증(자동차) API 로그 적재 — 자동차 수집 OFF(carEnabled=false)면 적재 생략(CAT002 슬롯 미생성).","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":761,"line_end":761,"block_type":"line","text":"* B2C order_detail 업데이트 (transactionId 갱신) - 진행 중 상태","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":765,"line_end":765,"block_type":"line","text":"자료분석중","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":768,"line_end":768,"block_type":"line","text":"* B2C 진료 데이터 처리: B2C 전용 테이블에 저장 및 분석","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":793,"line_end":795,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 응답 저장 (B2C) — 실패해도 분석 플로우는 계속\n* result/data 필드가 비정상(undefined)이어도 동기 throw가 발생하지 않도록 try/catch + 옵셔널 체이닝 적용\n* 빈 리스트 응답에서도 createB2cMedicineSummary를 호출해 기존 stale 데이터를 정리 (N→0 케이스 대응)","hangul_chars":80,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":818,"line_end":818,"block_type":"line","text":"* B2C order_detail 완료 상태 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":820,"line_end":820,"block_type":"line","text":"분석완료","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":824,"line_end":824,"block_type":"line","text":"* B2C 분석 성공 시 알림톡 발송","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":846,"line_end":846,"block_type":"line","text":"* B2C order_detail 실패 상태 업데이트","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":848,"line_end":848,"block_type":"line","text":"분석실패","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":852,"line_end":852,"block_type":"line","text":"* B2C 분석 실패 시 알림톡 발송","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.event-handler.ts","lang":"js","line_start":858,"line_end":858,"block_type":"line","text":"B2C는 altCode를 fcmCode로 사용","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":28,"line_end":29,"block_type":"line","text":"* 벤더 진료 데이터 숫자 변환 가드: null/undefined/비숫자(폴백 라벨 오염 등)는 0으로.\n*  (과거 inhouse UI폴백 라벨오염값이 NaN→INSERT \"Unknown column 'NaN'\" 500→ODD004 유발했음.)","hangul_chars":40,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"* 기본진료정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"*병원/약국명에 해당 글자명이 포함되는지 확인","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"* 빈문자('')→NULL 정규화(벤더 통일)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":93,"line_end":93,"block_type":"line","text":"* 세부내역정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 처방조제정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":142,"line_end":143,"block_type":"line","text":"* 재분석 가드용: 수집된 진료 원본(tt_treat_basic)이 있는지. 없으면 재분석=빈 완료(가짜완료)가 되므로\n*   호출부(compare/userReAnalyze)에서 차단한다. 수집 실패건(인증오류·타임아웃 등)은 원본이 없다.","hangul_chars":63,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"* 주문 성공을 결정하는 건강 분석은 자동차와 별도 트랜잭션으로 먼저 확정한다.","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":164,"line_end":164,"block_type":"line","text":"* 자동차 분석은 내부 카나리 부가정보다. 조회/계산/INSERT 어느 단계가 실패해도 건강 성공을 유지한다.","hangul_chars":38,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":166,"line_end":166,"block_type":"jsdoc","text":"자동차 분석 시작","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 진료정보_자동차(기본) 조회 - 상세는 저장은 해두나 현재 데이터는 미사용","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":174,"line_end":174,"block_type":"line","text":"* 그룹 indedx(같은 그룹일 경우 동일한 index로 처리)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":177,"line_end":177,"block_type":"line","text":"* 분석 기본, 상세 객체 선언","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":208,"line_end":209,"block_type":"line","text":"* 자동차 진료정보(기본)을 통한 진료시작일 기준 3개월 차이가 나는 데이터 그룹화 및 계산\n* 자동차 진료정보(기본)이 없을 시 계산 실행 X","hangul_chars":52,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 계산된 배열에서 마지막 요소만 가져옴","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":216,"line_end":217,"block_type":"line","text":"* 계산된 배열 마지막 요소가 없을 경우\n* 현재 루프의 item 진료시작일과 계산된 배열 마지막 진료시작일 간의 차이가 3개월 날 경우","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":259,"line_end":259,"block_type":"line","text":"그룹별 합산","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":321,"line_end":321,"block_type":"jsdoc","text":"자동차 분석 종료","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":323,"line_end":323,"block_type":"line","text":"* 자동차 INSERT는 별도 트랜잭션으로 묶어 부분 저장을 방지한다.","hangul_chars":23,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":326,"line_end":326,"block_type":"line","text":"* 자동차 분석 추가(데이터 값이 있을 때만 실행)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":337,"line_end":337,"block_type":"line","text":"날짜 계산을 위해 했던 정렬을 역순으로 재조정","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":361,"line_end":361,"block_type":"line","text":"* 기본, 상세 데이터(자동차)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":366,"line_end":366,"block_type":"line","text":"* 자동차 진료정보 (Client 방식: 속성명 fallback 지원)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":371,"line_end":371,"block_type":"line","text":"* 기본진료정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":384,"line_end":384,"block_type":"line","text":"*병원/약국명에 해당 글자명이 포함되는지 확인","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":408,"line_end":408,"block_type":"line","text":"* 세부내역정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":503,"line_end":504,"block_type":"line","text":"* 정회원: 심평원 '내가 먹는약 한눈에' 응답 저장\n* 빈 리스트 입력 시에도 기존 데이터 삭제까지 수행하여 N→0 케이스의 stale 데이터를 정리","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":525,"line_end":525,"block_type":"line","text":"* 재분석 대비 기존 데이터 삭제 후 삽입(멱등 처리). 트랜잭션으로 묶어 부분 실패 시 롤백.","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":536,"line_end":537,"block_type":"line","text":"* B2C: 심평원 '내가 먹는약 한눈에' 응답 저장\n* 빈 리스트 입력 시에도 기존 데이터 삭제까지 수행하여 N→0 케이스의 stale 데이터를 정리","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":558,"line_end":558,"block_type":"line","text":"* 재분석 대비 기존 데이터 삭제 후 삽입. delete/insert를 한 트랜잭션에 묶어 부분 실패 시 롤백.","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":569,"line_end":569,"block_type":"line","text":"* 'YYYYMMDD' / 'YYYY-MM-DD' 입력 모두를 'YYYY-MM-DD'로 정규화","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":580,"line_end":584,"block_type":"jsdoc","text":"B2C 진료 데이터 분석 및 저장\n@param bodId B2C order detail ID\n@param dto B2C 진료 데이터 (transactionId, codefResultCode, medical, car)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":589,"line_end":589,"block_type":"line","text":"Codef 결과 코드 (CF-00000, CF-03002 등)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":597,"line_end":597,"block_type":"line","text":"1. 재분석을 위해 기존 임시 데이터 삭제","hangul_chars":15,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":600,"line_end":600,"block_type":"line","text":"2. medical 데이터 저장 (임시 테이블에 저장)","hangul_chars":13,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":603,"line_end":603,"block_type":"line","text":"3. 주문 성공을 결정하는 B2C 건강 분석을 자동차와 분리해 먼저 확정","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":612,"line_end":612,"block_type":"line","text":"4. 자동차 저장/분석은 어느 단계가 실패해도 B2C 건강 성공을 유지","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":617,"line_end":617,"block_type":"line","text":"car 데이터 저장 (있을 경우, 임시 테이블에 저장) - Client 방식 조건문","hangul_chars":22,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":624,"line_end":624,"block_type":"line","text":"5. B2C 분석 실행","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":627,"line_end":627,"block_type":"line","text":"자동차 분석 로직 (정회원과 동일)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":711,"line_end":711,"block_type":"line","text":"그룹별 합산","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":770,"line_end":770,"block_type":"line","text":"자동차 INSERT만 별도 트랜잭션으로 처리해 부분 저장 방지","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":772,"line_end":772,"block_type":"line","text":"자동차 분석 추가","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":810,"line_end":812,"block_type":"jsdoc","text":"B2C 기본 진료 데이터 저장 (medical)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":818,"line_end":818,"block_type":"line","text":"기본진료정보 (임시 테이블에 저장)","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":846,"line_end":846,"block_type":"line","text":"* 빈문자('')→NULL 정규화(벤더 통일)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":851,"line_end":851,"block_type":"line","text":"세부내역정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":869,"line_end":869,"block_type":"line","text":"처방조제정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":892,"line_end":892,"block_type":"line","text":"임시 테이블에 저장 (정회원 방식과 동일)","hangul_chars":16,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":906,"line_end":908,"block_type":"jsdoc","text":"B2C 자동차 진료 데이터 저장 (Client 방식: 속성명 fallback, null safety, 영상의학과 체크)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":913,"line_end":913,"block_type":"line","text":"* 자동차 진료정보 (Client 방식: 속성명 fallback 지원)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":918,"line_end":918,"block_type":"line","text":"* 기본진료정보 (임시 테이블에 저장)","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":931,"line_end":931,"block_type":"line","text":"*병원/약국명에 해당 글자명이 포함되는지 확인","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":955,"line_end":955,"block_type":"line","text":"* 세부내역정보 (임시 테이블에 저장)","hangul_chars":14,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":986,"line_end":986,"block_type":"line","text":"임시 테이블에 저장 (정회원 방식과 동일)","hangul_chars":16,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":997,"line_end":1000,"block_type":"jsdoc","text":"B2C 재분석을 위한 임시 테이블 데이터 삭제\n동일 bodId로 재분석 시 기존 임시 데이터 삭제 필요","hangul_chars":34,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":1014,"line_end":1014,"block_type":"jsdoc","text":"B2C 자동차 임시 데이터는 건강 임시 데이터와 분리해 best-effort로 정리한다.","hangul_chars":25,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":1026,"line_end":1030,"block_type":"jsdoc","text":"B2C 재분석을 위한 자동차 분석 테이블 데이터 삭제\n프로시저에서 basic/detail/prescribe 테이블은 DELETE 처리하므로\n코드에서는 자동차 분석 테이블만 삭제","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.repository.ts","lang":"js","line_start":1033,"line_end":1033,"block_type":"line","text":"자동차 분석 detail 먼저 삭제 (FK 제약 때문)","hangul_chars":13,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":113,"line_end":114,"block_type":"line","text":"* 진료내역 스크래핑 공급자 스위치 (configuration.treatProvider: 'codef'(기본)|'coocon')\n* CodefService·CooconService 모두 TreatScraper(fetchCertifyMultiple/fetchTreatmentMultiple)를 만족","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":345,"line_end":346,"block_type":"line","text":"* 자동차보험 진료 수집 ON/OFF는 TreatProviderService.isCarEnabled()로 일원화\n*   (DB tn_treat_setting 우선, env enableTreatCar 폴백). 운영 중 어드민 토글로 즉시 차단/복구.","hangul_chars":33,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":348,"line_end":352,"block_type":"jsdoc","text":"심평원 개인인증 요청\n성공 : 알림톡 사용완료 O | 주문상세 create 상태값(인증요청중) | FC 알람 X\n실패 : 알림톡 사용완료 X | 주문상세 create X | FC 알람 X","hangul_chars":47,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":354,"line_end":354,"block_type":"line","text":"* 심평원 기관 사용중지 여부 우선 확인 (관리자 설정)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":357,"line_end":359,"block_type":"line","text":"* 사전 입력검증 (체크섬·생년월일·성별/세기코드·만14세·이름) — 잘못된 입력이\n* 대기열/codef 슬롯을 점유하기 전에 진입 차단. 실패 시 명확한 코드/메시지 반환.\n* \"이름↔주민 실존 매핑\"은 본인확인기관(NICE/KCB) 영역이라 여기서 불가 → codef 본인인증이 담당.","hangul_chars":89,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":368,"line_end":371,"block_type":"line","text":"* [실명확인 hook] NICE/KCB 실명확인 계약 시 활성 — SMS 없이 이름+주민 매핑만 사전확인,\n*   불일치면 여기서 차단(대기열·codef 진입 전). 현재 미계약이라 미사용.\n*   const real = await this.realNameService.verify(dto.usrName, dto.usrBirth + dto.identityNo);\n*   if (!real.matched) throw new BadRequestException({ code: 'NAME_MISMATCH', message: '이름과 주민등록번호가 일치하지 않습니다.' });","hangul_chars":69,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":379,"line_end":379,"block_type":"line","text":"* B2C 플로우인 경우 알림톡 검증 건너뛰기","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":381,"line_end":381,"block_type":"line","text":"B2C는 orderInfo 없이 진행 (agcCode를 altCode로 사용)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":384,"line_end":384,"block_type":"line","text":"* 알림톡 정보 찾기","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":394,"line_end":395,"block_type":"line","text":"* 초대링크 접근 유효성(구독종료/건수소진/결제취소) — 발송 후 만료된 선발송 링크 차단.\n*   만료/소진 시 EXPIRED_ACCESS_LINK(E0214) → 프론트 \"접근 기간 만료\" 화면.","hangul_chars":50,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":397,"line_end":397,"block_type":"line","text":"* 한도 검증 + 예약수 +1 (인증요청중 진입 시점 차감)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":405,"line_end":405,"block_type":"jsdoc","text":"심평원인증요청 (다건요청: 기본+자동차를 단일 인증으로 처리)","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":410,"line_end":410,"block_type":"line","text":"민감상병표기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":411,"line_end":411,"block_type":"line","text":"동일계정으로 구분값이 필요할 경우 암호화 해서 넣기","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":423,"line_end":425,"block_type":"line","text":"* 1차 진입점에서는 건강만 넘긴다. 멀티 디스패처가 공급자를 고른 뒤,\n* master+canary가 모두 ON인 inhouse 요청에만 자동차를 합성한다.\n* 단일 외부 공급자 구성은 자동차를 fail-closed로 유지한다.","hangul_chars":62,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":429,"line_end":429,"block_type":"line","text":"* [1단계] 대기열 재요청이면 기존 queueId 인계 → 멀티 디스패처가 만석 시 순번 유지(단일 공급자는 무시)","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":435,"line_end":437,"block_type":"line","text":"* 벤더 응답에 transactionId 없으면(자체엔진 등 다건) 여기서 1회 생성해 codef에 주입 →\n*   log_treat(1차)와 tn_order_detail(addOrderDetail)이 같은 분석번호를 공유한다.\n*   미주입 시 자체엔진은 로그=빈값/주문='a'+uuid 로 단절되어 주문↔호출 추적·모니터 집계가 깨짐.","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":441,"line_end":441,"block_type":"line","text":"* codef response가 반환된 시점에 codef 결과 로그 적재 (정회원만)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":443,"line_end":443,"block_type":"line","text":"정회원: 1차 인증 로그 기록","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":451,"line_end":452,"block_type":"line","text":"* 대기열 진입(CF-QUEUE, multi 디스패처): 아직 인증 전이므로 예약수 환불(재요청 시 재차감), odd 미생성.\n* 클라는 응답의 queueId로 순번 폴링 → READY면 동일 certify를 재요청한다.","hangul_chars":52,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":462,"line_end":462,"block_type":"line","text":"* 알람 및 detail 추가 X / 에러코드 반환값","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":464,"line_end":464,"block_type":"line","text":"* CODEF 인증 실패: 예약수 환불 (알림톡 플로우만, odd 생성 전이라 단순 -1)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":470,"line_end":470,"block_type":"line","text":"* 1차 라우팅 벤더(dispatcher가 응답에 부착) → filter에서 coocon/hyphen 코드 정확 분류","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":482,"line_end":496,"block_type":"line","text":"* 간편인증(loginType='5') 요청 직후 인증확인 알림톡 발송\n* OK마이보험처럼 인증 대상자에게 '본인 인증앱에서 인증 확인'을 안내한다.\n* 인증요청 응답을 지연/실패시키지 않도록 await 없이 fire-and-forget 처리한다.\n* [task-05 보류] 알림톡 템플릿코드(ALIGO_CERT_CONFIRM_TEMPLATE_CODE) 승인 전까지 비활성화 — 인프라 후 주석 해제\nif (dto.loginType === '5') {\n  this.alimtalkService\n    .sendCertConfirm({\n      usrName: dto.usrName,\n      usrPhone: dto.usrPhone,\n      ordId: orderInfo?.order?.ordId,\n    })\n    .catch((e) => {\n      this.logger.error(`인증확인 알림톡 발송 실패: ${e}`);\n    });\n}","hangul_chars":107,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":498,"line_end":498,"block_type":"line","text":"* B2C 플로우: B2C 사용자 생성 및 order_detail 생성","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":500,"line_end":500,"block_type":"line","text":"* B2C 사용자 생성 또는 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":514,"line_end":514,"block_type":"line","text":"* B2C order_detail 생성 (정회원과 동일하게 certify 시점에 생성)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":518,"line_end":518,"block_type":"line","text":"* 분석번호: 벤더 응답에 transactionId 없으면(다건 등) 자체 생성 (주문번호와 동일 방식)","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":527,"line_end":527,"block_type":"line","text":"* B2C: 1차 인증 로그 기록 (B2C order_detail 생성 이후)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":548,"line_end":548,"block_type":"line","text":"B2C는 bodId를 oddId로 반환","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":556,"line_end":556,"block_type":"line","text":"* 고객 정보 추가 (알림톡 플로우만)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":564,"line_end":564,"block_type":"line","text":"* usrId가 주문상세에서 null 허용으로 변경되어 검증 추가","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":569,"line_end":569,"block_type":"line","text":"* 주문상세(분석)목록 추가 및 알림톡 [사용] update","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":574,"line_end":574,"block_type":"line","text":"* 분석번호: 벤더 응답에 transactionId 없으면(다건 등) 자체 생성 (주문번호 'o'+newUuid 와 동일 방식)","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":577,"line_end":577,"block_type":"line","text":"* 1차 인증 라우팅된 공급자를 생성 시점부터 기록 → 인증실패도 업체 귀속 (멀티 디스패처)","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":596,"line_end":601,"block_type":"jsdoc","text":"심평원 개인인증확인 및 진료정보요청\n성공 : 알림톡 사용완료 O | 주문상세 update 상태값(자료수집중) | FC 알람 X\n실패(재시도가능) : 알림톡 사용완료 O | 주문상세 update 상태값(추가인증요청중) | FC 알람 X\n실패(사용불가) : 알림톡 사용완료 O | 주문상세 update 상태값(인증싶패) | FC 알람 O","hangul_chars":95,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":603,"line_end":603,"block_type":"line","text":"* 심평원 기관 사용중지 여부 우선 확인 (관리자 설정)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":606,"line_end":606,"block_type":"line","text":"주문상세 정보 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":617,"line_end":617,"block_type":"line","text":"민감상병표기","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":620,"line_end":620,"block_type":"line","text":"동일계정으로 구분값이 필요할 경우 암호화 해서 넣기","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":631,"line_end":631,"block_type":"line","text":"* 2차 진료정보 요청시 필요값","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":632,"line_end":632,"block_type":"line","text":"보안문자 이미지정보(필수)","hangul_chars":11,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":633,"line_end":633,"block_type":"line","text":"보안문자 새로고침 \"0\": 기본, \"1\": 재요청, \"2\" : 입력취소(default:0)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":634,"line_end":634,"block_type":"line","text":"[SMS 인증]필수","hangul_chars":4,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":635,"line_end":635,"block_type":"line","text":"! 추가확인필요 \"0\": cancel , \"1\": ok","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":636,"line_end":636,"block_type":"line","text":"인증후 요청일 시 true 고정","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":645,"line_end":648,"block_type":"line","text":"* 2차 자료수집을 다건(배열)으로 발사 - 공유 twoWayInfo를 전 요소에 동일 적용 (index 0=기본, 1=자동차)\n* 자동차요소(index 1)는 원본 carData와 동일한 자동차 수집 파라미터(organization '0020'/type '1' 민감상병표기/id)를\n* 명시적으로 유지한다. 상품 구분자는 inquiryType만 사용하며, 다건전환으로 자동차 전용 파라미터가 누락되지 않도록 명시한다.\n* 자동차(inquiryType='1')는 자동차 수집 OFF면 제외 (기능 OFF, 코드는 보존)","hangul_chars":124,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":659,"line_end":659,"block_type":"line","text":"공통값(원본 carData와 동일)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":660,"line_end":660,"block_type":"line","text":"민감상병표기(원본 carData와 동일)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":663,"line_end":663,"block_type":"line","text":"동일계정 구분값(원본 carData와 동일 소스)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":679,"line_end":681,"block_type":"line","text":"* index 0=기본, 1=자동차로 역다중화\n* 다건 API는 배치 전체에 대한 공유 result 1세트만 반환하므로(항목별 result 미제공)\n* 자동차 개별 성공/실패를 result.code로 구분할 수 없다. 자동차 포함 여부는 아래 data[1] 길이로만 판정(부분허용 정책).","hangul_chars":75,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":685,"line_end":686,"block_type":"line","text":"* idx0(기본) 실패 시 전체 실패 처리\noddId, orderDetail.member.memId, dto.usrName 추가필요","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":696,"line_end":696,"block_type":"line","text":"//*  임시데이터 저장","hangul_chars":7,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":712,"line_end":712,"block_type":"line","text":"* 주문상세이력상태변경(인증확인에러) //자료수집에러","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":718,"line_end":718,"block_type":"line","text":"* 인증실패: 예약수 환불","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":726,"line_end":726,"block_type":"line","text":"자부상 기본, 상세 데이터 create 기능 추가(2025-03-10)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":731,"line_end":731,"block_type":"line","text":"* 부분허용 정책: 자동차 데이터 부재(미수집)는 정상 경로이므로 옵셔널/빈배열 기본값으로 안전 처리","hangul_chars":40,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":740,"line_end":740,"block_type":"line","text":"* 자동차는 내부 카나리 부가정보다. 저장 실패가 건강 진료 성공/주문 상태를 뒤집지 않는다.","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":756,"line_end":756,"block_type":"line","text":"* 심평원 기관 사용중지 여부 우선 확인 (관리자 설정)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":759,"line_end":759,"block_type":"line","text":"* B2C 플로우: 진료정보 수집 후 고객사 API로 분석 처리","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":763,"line_end":763,"block_type":"line","text":"* eventEmitter를 통해 비동기적 작업 분리 (정회원과 동일)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":768,"line_end":768,"block_type":"line","text":"주문상세 정보 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":771,"line_end":771,"block_type":"line","text":"* SMS 제출과 OTP 만료 정리 중 정확히 한쪽만 DB 행을 선점한다.","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":779,"line_end":779,"block_type":"line","text":"* eventEmitter를 통해 비동기적 작업 분리","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":785,"line_end":789,"block_type":"jsdoc","text":"심평원 진료정보 분석요청\n성공 : 알림톡 사용완료 O | 주문상세 update 상태값(분석중->분석완료) | FC 알람 O\n실패 : 알림톡 사용완료 O | 주문상세 update 상태값(분석중->분석완료) | FC 알람 O","hangul_chars":61,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":790,"line_end":797,"block_type":"jsdoc","text":"유저 재시도(분석실패/자료수집완료 → 재분석) 진입점.\n관리자 재분석과 동일하게 [기존 분석결과 삭제 + 잔여량 검증 후 예약(차감)] 을 먼저 수행한 뒤 분석.\n- 유저는 항상 차감(charge=true): 분석완료 시 사용수 +1, 재시도 실패 시 예약 환불.\n- 재시도 불가 상태(분석중/완료 등)면 ConflictException 으로 차단(중복분석·중복차감 방지).\n- 잔여량 초과면 prepareReAnalyze 내부에서 ORDER_NOT_AVAILABLE(400).\n  (이전에는 기존 분석결과를 안 지우고 재분석 → tn_analysis_basic PK 중복 → 404 발생)","hangul_chars":144,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":801,"line_end":801,"block_type":"line","text":"* getOrderDetail 은 GET_STATUS 로 라벨을 반환(코드 아님).","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":804,"line_end":804,"block_type":"line","text":"* 진행/완료 건 재시도 차단(중복분석·중복차감 방지). 분석실패/자료수집완료 등은 통과.","hangul_chars":34,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":809,"line_end":811,"block_type":"line","text":"* 재분석 가드: 수집된 원본이 없으면 차감(prepareReAnalyze) 전에 차단 → 헛차감·가짜완료 방지.\n*   수집 실패건(인증오류·처리중오류·타임아웃 등)은 재분석할 원본이 없고, 재수집은 고객 재인증이\n*   필요해 재시도로 복구 불가하므로 여기서 막는다. (compare에도 동일 가드 — 방어 이중화)","hangul_chars":99,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":816,"line_end":816,"block_type":"line","text":"* 기존 분석결과 삭제 + 잔여량 검증 후 예약(차감). PK 중복 방지 + 한도 초과 차단.","hangul_chars":28,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":823,"line_end":823,"block_type":"line","text":"* 분석 실행(분석완료 시 addQuantity 로 차감 확정, 실패 시 예약 환불).","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":828,"line_end":828,"block_type":"line","text":"* 심평원 기관 사용중지 여부 우선 확인 (관리자 설정)","hangul_chars":20,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":839,"line_end":842,"block_type":"line","text":"* 재분석 가드: 수집된 진료 원본(tt_treat_basic)이 없으면 재분석 불가 → '가짜완료' 방지.\n*   인증/수집 실패건(인증오류·처리중오류·타임아웃 등)은 분석할 원본이 없는데,\n*   재분석을 돌리면 createAnalyze가 무에러로 빈 결과를 만들어 '분석완료(ODD006)'로 오인된다.\n*   원본 수집은 고객 본인인증이 다시 필요해 재시도로 복구 불가하므로 진입 자체를 차단한다.","hangul_chars":123,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":848,"line_end":849,"block_type":"line","text":"* 분석과 재분석의 상태변경이 달라야 하는지?\n* 주문상세이력상태변경(분석요청)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":852,"line_end":852,"block_type":"line","text":"분석요청","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":855,"line_end":856,"block_type":"line","text":"* 분석\n* 2025-03-12 기준 내부 로직에 자동차 진료기록 분석도 포함","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":860,"line_end":860,"block_type":"line","text":"* 주문상세이력상태변경(분석실패) - 상태 변경을 먼저 실행","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":880,"line_end":880,"block_type":"line","text":"* 분석실패: 예약수 환불","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":888,"line_end":888,"block_type":"line","text":"* Order 카운트 추가 (예약 → 완료 전환)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":891,"line_end":892,"block_type":"line","text":"* 임시데이터 삭제\nawait this.treatRepository.delete(oddId);","hangul_chars":7,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":894,"line_end":894,"block_type":"line","text":"* 분석성공시","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":902,"line_end":902,"block_type":"line","text":"* 주문상세이력상태변경(분석완료)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":916,"line_end":916,"block_type":"line","text":"* 잘못된 개인정보입니다.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":924,"line_end":924,"block_type":"line","text":"* 앱을 설치하지 않았거나 인증서를 발급받지 않으셨습니다.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":940,"line_end":940,"block_type":"line","text":"* CF-03002의 경우 인증을 하지 않고 인증확인을 했을 경우(재사용가능)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":953,"line_end":953,"block_type":"line","text":"* 주문상세이력상태변경(인증확인에러)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":959,"line_end":959,"block_type":"line","text":"* 인증실패: 예약수 환불","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":994,"line_end":999,"block_type":"line","text":"----------------------------- OnEvent -----------------------------//\n* 기존이벤트처리\nthis.eventEmitter.emit(\n  'order.created',\n  new OrderCreatedEvent(dto.oddId, codefData),\n);","hangul_chars":7,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":1017,"line_end":1055,"block_type":"line","text":"//*  임시데이터 저장\n    const addTreat = {\n      resBasicTreatList: codef.data!.resBasicTreatList!,\n      resDetailTreatList: codef.data!.resDetailTreatList!,\n      resPrescribeDrugList: codef.data!.resPrescribeDrugList!,\n    };\n    await this.addTreat(payload.oddId, addTreat);\n  } catch {\n    await this.alarmService.addAlarm({\n      memId: alarmInput.memId,\n      usrId: alarmInput.usrId,\n      almState: 'ODD003',\n      almMessage: '자료수집 중 에러가 발생했습니다.',\n    });\n    //* 주문상세이력상태변경(요청에러)\n    await this.orderDetailService.updateOrderDetailStatus({\n      oddId: alarmInput.oddId,\n      oddState: OrderDetailState.ODD003, //요청에러\n      oddFailedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),\n    });\n    return;\n  }\n  //* 분석요청하기\n  await this.compare({ oddId: payload.oddId }, false).catch(async (e) => {\n    await this.alarmService.addAlarm({\n      memId: alarmInput.memId,\n      usrId: alarmInput.usrId,\n      almState: 'ODD004',\n      almMessage: '분석에 실패했습니다.',\n    });\n    //* 주문상세이력상태변경(분석실패)\n    await this.orderDetailService.updateOrderDetailStatus({\n      oddId: alarmInput.oddId,\n      oddState: OrderDetailState.ODD004, //분석실패\n      oddFailedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),\n    });\n  });\n  return;\n}","hangul_chars":72,"class":"4_todo","tags":["4_todo","5_dead"],"classified_by":"keyword","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":1057,"line_end":1066,"block_type":"line","text":"@OnEvent('reanalyze.created')\nasync handleReanalyzeCreated(payload: ReanalyzeEvent) {\n  const orderDetail = await this.orderDetailService.getOrderDetail(\n    payload.oddId,\n  );\n  //* 주문상세이력상태변경(분석요청)\n  await this.orderDetailService.updateOrderDetailStatus({\n    oddId: payload.oddId,\n    oddState: OrderDetailState.ODD006, //재분석요청일시는 updated_at\n  });","hangul_chars":22,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":1068,"line_end":1080,"block_type":"line","text":"await this.drizzle\n    .transaction(async (tx) => {\n      await tx.execute(sql`CALL PROC_COMPARE_BASIC(${payload.oddId})`);\n      await tx.execute(sql`CALL PROC_COMPARE_DETAIL(${payload.oddId})`);\n      await tx.execute(sql`CALL PROC_COMPARE_PRESCRIBE(${payload.oddId})`);\n    })\n    .catch(async (e) => {\n      await this.alarmService.addAlarm({\n        memId: orderDetail.member!.memId,\n        usrId: orderDetail.user!.usrId!,\n        almState: 'ODD004',\n        almMessage: '분석에 실패했습니다.',\n      });","hangul_chars":9,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":1082,"line_end":1089,"block_type":"line","text":"//* 주문상세이력상태변경(분석실패)\n      await this.orderDetailService.updateOrderDetailStatus({\n        oddId: payload.oddId,\n        oddState: OrderDetailState.ODD004, //분석실패\n        oddFailedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),\n      });\n      throw '분석에 실패했습니다.';\n    });","hangul_chars":27,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/treat/treat.service.ts","lang":"js","line_start":1091,"line_end":1106,"block_type":"line","text":"//* 분석성공 시\n  await this.alarmService.addAlarm({\n    memId: orderDetail.member!.memId,\n    usrId: orderDetail.user!.usrId,\n    almState: 'ODD005',\n    almMessage: '분석이 완료되었습니다.',\n    almRedirectId: payload.oddId,\n  });\n  //* 주문상세이력상태변경(분석완료)\n  await this.orderDetailService.updateOrderDetailStatus({\n    oddId: payload.oddId,\n    oddState: OrderDetailState.ODD005, //분석완료\n    oddCompletedAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),\n  });\n  return;\n}","hangul_chars":33,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":40,"line_end":40,"block_type":"line","text":"* 기업관리자가 접근시 - 자신의 기업(agcId)으로 필터링","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 조직관리자(ORG)는 자기 org 부분트리만(다른 목록 API와 동일 스코프)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":49,"line_end":49,"block_type":"line","text":"* 영업대리점 로그인일 경우 리턴 데이터 마스킹 처리","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":104,"line_end":104,"block_type":"line","text":"* 영업대리점(관리자)가 접근시","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user-admin.controller.ts","lang":"js","line_start":109,"line_end":109,"block_type":"line","text":"* 기업관리자: 자기 기업만 + 조직관리자(ORG)는 부분트리만 (목록 조회와 동일 스코프)","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.dto.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* 조직관리자 부분트리 스코프(서버 내부 주입, 클라 미노출) — org_path LIKE prefix","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.repository.ts","lang":"js","line_start":190,"line_end":190,"block_type":"line","text":"* 조직관리자 부분트리 스코프 — 회원 소속 org가 관리 org_path 하위인 것만.","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.repository.ts","lang":"js","line_start":207,"line_end":207,"block_type":"line","text":"* 영업대리점 채널 코드","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.repository.ts","lang":"js","line_start":233,"line_end":233,"block_type":"line","text":"! 추후 memLoginId 조회 조건 추가되는 경우 해당부분 수정 및 전용 API 생성 필요","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.repository.ts","lang":"js","line_start":316,"line_end":316,"block_type":"jsdoc","text":"기업 ID로 회원 목록 조회","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.repository.ts","lang":"js","line_start":332,"line_end":332,"block_type":"jsdoc","text":"회원 ID로 회원 조회","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.service.ts","lang":"js","line_start":15,"line_end":15,"block_type":"jsdoc","text":"고객목록","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.service.ts","lang":"js","line_start":36,"line_end":36,"block_type":"jsdoc","text":"고객 목록 엑셀다운로드","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.service.ts","lang":"js","line_start":82,"line_end":82,"block_type":"jsdoc","text":"고객 저장여부확인","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/modules/user/user.service.ts","lang":"js","line_start":93,"line_end":93,"block_type":"jsdoc","text":"엑셀 다운로드 컬럼","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/alimtalk-status.schedule.ts","lang":"js","line_start":6,"line_end":14,"block_type":"jsdoc","text":"알리고 발송완료여부 스케줄러\n동작주기 : 5분 (참고 : 유저측에 알림톡목록이 있을 경우 조금 더 느슨하게 가도 됨)\naltMid의 값이 있고(없는경우 테스트모드), altRequestState가 [성공]이고 altCompletionState의 값이 빈값인 경우\n알림톡 발송요청 [성공]후 실제 발송완료여부를 체크하여\naltCompletionState와, altCompletionMessage의 값을 업데이트합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":125,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/analysis-stall.schedule.ts","lang":"js","line_start":7,"line_end":15,"block_type":"jsdoc","text":"분석 stall 처리 스케줄러\n동작주기 : 10분 (AWS EventBridge)\n자료수집완료(ODD002) / 자료분석중(ODD005) 상태가 1시간 경과되었고 최종분석상태 미박힘 인 경우\n→ odd_final_state = 분석실패(ODD007) 박고 예약수 환불 (1회 가드 마커 사용)\n\nraw odd_state 는 변경하지 않음 (관리자가 원본 진행상태 보존하기 위함).\n사용자/관리자 노출은 final_state 우선.","hangul_chars":98,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/analysis-stall.schedule.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"* 예약수 정합성 보정 (환불 누수 자가치유)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/analysis-status.schedule.ts","lang":"js","line_start":8,"line_end":16,"block_type":"jsdoc","text":"주문상세(분석) 상태변경 스케줄러\n동작주기 : 5분 (AWS EventBridge)\n인증요청중(ODD001) / 추가인증요청중(ODD003) 상태가 일정시간 경과 + 최종분석상태 미박힘 인 경우\n→ odd_final_state = 인증실패(ODD004) 박고 예약수 환불 (1회 가드 마커 사용)\n\nraw odd_state 는 변경하지 않음 (관리자 화면에서 원본 진행상태 보존하기 위함).\n사용자/관리자 노출은 final_state 우선.","hangul_chars":107,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/analysis-status.schedule.ts","lang":"js","line_start":28,"line_end":28,"block_type":"line","text":"* 예약수 정합성 보정 (환불 누수 자가치유). stale 정산 직후 실행해 정확한 값으로 맞춤","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/analysis-status.schedule.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 모니터링 알림 — 어드민이 켠 종류의 위험 경고를 구글챗으로 발송(30분 중복억제 + 복구 알림)","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-analysis.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"심평원 분석결과정보 데이터 삭제\n동작주기 : 확인필요\n분석결과정보의 생성일이 30일이 지난 경우 분석결과정보 데이터를 삭제합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":74,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-fc.schdule.ts","lang":"js","line_start":6,"line_end":12,"block_type":"jsdoc","text":"탈퇴 회원 데이터 삭제\n동작주기 : 확인필요\n탈퇴 이후 일년이 지난 경우 유저 정보를 삭제합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":58,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":10,"line_end":17,"block_type":"jsdoc","text":"청구서 파일 삭제 스케줄러\n동작주기 : 매일 23:59:59 (한국시간 기준)\nivh_created_at 기준 30일이 지난 청구서의 S3 파일을 삭제하고\nivh_s3_key, ivh_attachment_s3_keys 컬럼을 NULL로 처리합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":69,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"스케줄러 전용 서비스 (의존성 최소화)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"파일이 없으면 스킵","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"S3 파일 삭제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":85,"line_end":85,"block_type":"line","text":"S3 삭제 실패해도 다음 파일 계속 처리","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":89,"line_end":89,"block_type":"line","text":"DB에서 S3 키 NULL 처리","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":108,"line_end":114,"block_type":"jsdoc","text":"S3 키 JSON 데이터 파싱\n- JSON 배열: [{s3Key: string, originalName: string}]\n- 문자열 배열: [\"key1\", \"key2\"]\n- JSON 문자열: \"[{...}]\"\n- 콤마 구분 문자열: \"key1,key2\"","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"1. 이미 객체 배열인 경우","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":123,"line_end":123,"block_type":"line","text":"객체 배열: [{s3Key: ..., originalName: ...}]","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"문자열 배열: [\"key1\", \"key2\"]","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":134,"line_end":134,"block_type":"line","text":"2. JSON 문자열인 경우","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"JSON 배열 문자열","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":142,"line_end":142,"block_type":"line","text":"재귀 호출","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":144,"line_end":144,"block_type":"line","text":"JSON 파싱 실패 시 상세 로그 출력","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"JSON 파싱 실패 시 안전하게 빈 배열 반환","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":157,"line_end":157,"block_type":"line","text":"콤마로 구분된 문자열","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"단일 문자열","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-invoice-files.schedule.ts","lang":"js","line_start":176,"line_end":176,"block_type":"line","text":"스케줄러 전용 최소 모듈","hangul_chars":10,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-treat.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"심평원 원본임시데이터 삭제\n동작주기 : 매일 오전 6시\n주문상세(분석)의 생성일이 30일이 지난 경우 심평원의 원본데이터를 삭제합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":73,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/delete-treat.schedule.ts","lang":"js","line_start":27,"line_end":36,"block_type":"line","text":"* 기존 스케줄러\nconst orderDetailService = app.get(OrderDetailService);\nconst list = await orderDetailService.getDeleteOrderDetailForSchedule();\nlogger.log(list);\nfor await (const item of list) {\n  logger.log(item);\n  await treatService.deleteTreatData(item.oddId).catch((error) => {\n    logger.log(error);\n  });\n}","hangul_chars":6,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/disable-subscription.schedule.ts","lang":"js","line_start":6,"line_end":12,"block_type":"jsdoc","text":"해지처리 스케줄러\n동작주기 : 매일 자정\n구독상태가 [해지]이고 subNextPayDay의 날짜가 지났을 경우 해지완료일처리를 합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":65,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/disable-subscription.schedule.ts","lang":"js","line_start":22,"line_end":32,"block_type":"line","text":"* 기존 스케줄러\nconst list = await subscribeService.getSubscriptionDisable();\nlogger.log(list);\nfor await (const item of list) {\n  logger.log(item);\n  await subscribeService\n    .reservationForUnsubscribe(item.subId)\n    .catch((error) => {\n      logger.log(error);\n    });\n}","hangul_chars":6,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/expired-money.schedule.ts","lang":"js","line_start":6,"line_end":12,"block_type":"jsdoc","text":"머니 소멸 스케줄러\n동작주기 : 매일 자정 (AWS EventBridge에서 설정)\n유효기간이 만료된 적립/지급 머니의 잔액을 소멸 처리합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":65,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/fax-status.schedule.ts","lang":"js","line_start":6,"line_end":16,"block_type":"jsdoc","text":"FAX 발송 상태 체크 스케줄러\n동작주기 : 1분 (AWS EventBridge에서 설정)\nfxh_delivery_status가 PENDING인 팩스 건에 대해\nvFax API로 발송 결과를 조회하여 상태를 업데이트합니다.\n- 결과수신 시: SUCCESS 또는 FAILED 처리 (실패 시 머니 환불)\n- 3시간 초과 시: FAILED 처리 (응답 시간 초과)\n- 배치 전체 완료 시: 알림 발송\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":107,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/regular-agency-subscription.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"기업FC 정기구독결제 스케줄러\n동작주기 : 매일 아침 9시 / 저녁 18시\n구독상태가 [구독] 또는 [변경]이고 구독결제일의 대상자를 선택하여 정기결제 및 주문처리를 합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":84,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/regular-subscription.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"일반FC 정기구독결제 스케줄러\n동작주기 : 매일 아침 9시 / 저녁 18시\n구독상태가 [구독] 또는 [변경]이고 구독결제일의 대상자를 선택하여 정기결제 및 주문처리를 합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":84,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/sales-statistics.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"영업대리점 데일리 통계 발송\n동작주기 : 오후 7시\n영업대리점 데일리 통계 정보를 메일 발송 처리\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":58,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/settlement-agency.schedule.ts","lang":"js","line_start":7,"line_end":17,"block_type":"jsdoc","text":"기업 정산 스케줄러\n동작주기 : 매월 1일 자정\n모든 기업 조회 후 기업별 구독건수에 따른 정산데이터를 진행합니다.\n - FREE 과금(활성 계약 act_billing_type='FREE') 기업은 집계에서 제외됩니다.\n - 전월 정산에서 이월(CARRYOVER) 처리된 주문은 신규 정산 map에\n   INCLUDE + som_carryover_from_ast_id 로 편입되어 정산수/정산금액에 포함됩니다.\n - 생성되는 정산의 ast_settle_status는 'PENDING'(미정산) 입니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":134,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/settlement-agency.schedule.ts","lang":"js","line_start":26,"line_end":26,"block_type":"line","text":"* SETTLE_TARGET_DATE(YYYY-MM-DD) 지정 시 해당 날짜 기준으로 집계 — 로컬/수동 테스트용. 미지정 시 전월(운영 기본).","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"apps/api/src/schedules/settlement-client.schedule.ts","lang":"js","line_start":7,"line_end":13,"block_type":"jsdoc","text":"기업 정산 스케줄러\n동작주기 : 매월 1일 자정\n모든 기업 조회 후 기업별 구독건수에 따른 정산데이터를 진행합니다.\n\n해당 로직은 AWS EventBridge에서 실행되도록 설정되어 있습니다.","hangul_chars":65,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0001_institution_block.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"기관별 일시 사용중지 설정 테이블 신설 (심평원/국세청)\n운영 DB에 직접 적용해주세요. (drizzle introspection 기준 스냅샷)","hangul_chars":38,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0001_institution_block.sql","lang":"sql","line_start":19,"line_end":21,"block_type":"line","text":"> statement-breakpoint\n시드 INSERT 는 재실행/롤백 대비 idempotent 하게 처리 (isb_institution UNIQUE 제약 충돌 회피)\nIGNORE 사용 이유: 운영자가 이미 isb_blocked=1 등으로 설정해 둔 행을 덮어쓰지 않기 위함","hangul_chars":47,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0002_pms5_terms_org_medicine.sql","lang":"sql","line_start":1,"line_end":5,"block_type":"line","text":"5차 PMS 운영 DB 적용 SQL (task-12 약관 / task-16 조직·org_id / task-01·08 먹는약 summary)\n운영 DB에 직접 적용해주세요. (배포 파이프라인이 마이그레이션을 자동 적용하지 않음)\n모두 idempotent: 이미 존재하면 스킵되어 재실행해도 안전. 파괴적(DROP) 구문 없음.\n적용 후 task-16 org_id 백필: `node scripts/run-task688-migration.ts` (기본 조직 생성 + org_id 채움)\n참고: task-11(tn_institution_block)은 0001_institution_block.sql 참조.","hangul_chars":90,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0002_pms5_terms_org_medicine.sql","lang":"sql","line_start":7,"line_end":9,"block_type":"line","text":"─────────────────────────────────────────────\n[task-12] 기업별 약관\n─────────────────────────────────────────────","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0002_pms5_terms_org_medicine.sql","lang":"sql","line_start":26,"line_end":28,"block_type":"line","text":"─────────────────────────────────────────────\n[task-16] 기업 조직\n─────────────────────────────────────────────","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0002_pms5_terms_org_medicine.sql","lang":"sql","line_start":44,"line_end":44,"block_type":"line","text":"[task-16] org_id 컬럼 추가 (기존 테이블) — 컬럼이 이미 있으면 스킵","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0002_pms5_terms_org_medicine.sql","lang":"sql","line_start":53,"line_end":58,"block_type":"line","text":"─────────────────────────────────────────────\n[task-01 / task-08] 먹는약 summary\n · retention 삭제 배치(deleteExpiredData / deleteB2cExpiredData)가 이 테이블을 참조한다.\n · 없으면 배치가 깨지므로 task-01 비활성과 무관하게 반드시 존재해야 함.\n · tt_b2c_treat_medicine_summary 는 stg 에도 없던 누락분.\n─────────────────────────────────────────────","hangul_chars":51,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":1,"line_end":3,"block_type":"line","text":"진료 스크래핑 멀티 공급자 — 처리업체 기록 + 공급자 설정 테이블\n운영 DB에 직접 적용해주세요. (배포 파이프라인이 마이그레이션을 자동 적용하지 않음)\n모두 idempotent: 이미 존재하면 스킵. 파괴적(DROP) 구문 없음.","hangul_chars":76,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":5,"line_end":7,"block_type":"line","text":"─────────────────────────────────────────────\n[처리업체 기록] tn_order_detail.odd_provider — 어느 공급자로 처리됐는지\n─────────────────────────────────────────────","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":12,"line_end":14,"block_type":"line","text":"─────────────────────────────────────────────\n[공급자 설정] tn_treat_provider — 멀티 디스패처 풀(단가/한도/사용여부). 관리자에서 조정.\n─────────────────────────────────────────────","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":30,"line_end":30,"block_type":"line","text":"기본 공급자 시드 (이미 있으면 무시). 단가: octover=1, coocon=2, codef=3(폴백·비활성)","hangul_chars":21,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":38,"line_end":41,"block_type":"line","text":"─────────────────────────────────────────────\n[관리자 메뉴] 진료 공급자 설정 — 사이트관리 하위(기관차단 옆), 동일 권한.\n · 부모/권한은 기존 기관차단(/site/institution-block) 메뉴에서 파생 → 환경별 ID 차이에 안전.\n─────────────────────────────────────────────","hangul_chars":53,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0003_treat_provider.sql","lang":"sql","line_start":49,"line_end":49,"block_type":"line","text":"권한 매핑: 기관차단 메뉴를 보는 권한과 동일하게 부여 (재실행 안전)","hangul_chars":27,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0004_treat_monitor_menu.sql","lang":"sql","line_start":1,"line_end":3,"block_type":"line","text":"진료 모니터링 메뉴 추가 (구독 관리 하위). 멱등 — 재실행 안전.\n사이드바는 tn_menu(DB)로 그려지므로 메뉴 행 + 권한매핑을 넣어야 노출됨.\n권한(ath)은 같은 구독>분석 관리(/subscription/analysis) 매핑을 그대로 복사하여 환경별 차이 대응.","hangul_chars":76,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0004_treat_monitor_menu.sql","lang":"sql","line_start":5,"line_end":5,"block_type":"line","text":"1) 메뉴 행 (없을 때만). 부모/depth 도 분석 관리에서 파생.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0004_treat_monitor_menu.sql","lang":"sql","line_start":19,"line_end":19,"block_type":"line","text":"2) 권한 매핑 — 분석 관리와 동일한 ath 들을 진료 모니터링에도 부여 (중복 무시).","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0005_treat_provider_hyphen.sql","lang":"sql","line_start":1,"line_end":5,"block_type":"line","text":"진료 스크래핑 공급자 시드 추가 — 하이픈(HYPHEN)\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\n⚠️ 적용 전 검토 필요. idempotent(INSERT IGNORE), 파괴적 구문 없음.\n기본 tpr_enabled=0(비활성): 실호출 검증 완료 후 관리자(진료 공급자 설정)에서 활성화할 것.\n단가(tpr_unit_cost)는 임시값 — 실제 요금제 확정 후 조정.","hangul_chars":107,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0006_log_treat_codef_provider.sql","lang":"sql","line_start":1,"line_end":3,"block_type":"line","text":"0006: log_treat 에 1차 인증 라우팅 공급자 컬럼 추가\n목적: order_detail이 생기지 않는 1차 인증실패도 어느 벤더로 보냈는지 귀속해 모니터링에서 벤더별로 보이게 함.\n적용: 수동 (스테이징/운영 각각 1회). 추가형 nullable 컬럼이라 무중단 안전.","hangul_chars":79,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0006_treat_provider_rate.sql","lang":"sql","line_start":1,"line_end":4,"block_type":"line","text":"진료 공급자 rate-limit(타임) 토글 컬럼 추가\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\nON(1)이면 디스패처가 해당 공급자를 'limitPerMin/flowCost = 분당 허용건수'로 rate-limit(sliding 60s).\nOFF(0, 기본)이면 기존처럼 동시 슬롯(maxFlows)으로만 동작. idempotent 아님(컬럼 존재 시 에러 → 1회만).","hangul_chars":92,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0007_log_treat_indexes.sql","lang":"sql","line_start":1,"line_end":12,"block_type":"line","text":"0007: log_treat 조회 성능 인덱스\n배경: log_treat 인덱스가 PK(ltr_id) 하나뿐 → 분석로그관리 목록(정렬 ltr_created_at +\n      상태/공급자 필터)이 매번 풀스캔 + filesort. 누적 행 많아질수록 선형으로 느려짐.\n효과:\n  idx_ltr_created       : 기본 목록 정렬 + 날짜범위 (제일 큼)\n  idx_status_created    : 실패만 보기(codef_result_status) + 정렬\n  idx_provider_created  : 처리업체(codef_provider) 필터 + 정렬\n  idx_odd_tx            : 거래번호 조회 + 모니터의 log_treat↔order_detail 조인\n적용: 수동 (스테이징/운영 각각 1회). 큰 테이블이므로 온라인 DDL(ALGORITHM=INPLACE, LOCK=NONE)로\n      무중단. 운영은 저트래픽 시간대 권장(인덱스 빌드 IO 발생). LOCK=NONE 미지원 시\n      pt-online-schema-change 사용.\n주의: 이름/휴대폰 검색은 AES_DECRYPT(...) LIKE 라 인덱스로 개선 불가(별도 과제).","hangul_chars":171,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0008_order_detail_indexes.sql","lang":"sql","line_start":1,"line_end":10,"block_type":"line","text":"0008: tn_order_detail 조회 성능 인덱스\n배경: tn_order_detail에 FK 인덱스(ord_id, usr_id)만 있고 정렬/필터 컬럼엔 인덱스 없음\n      → 분석관리 목록(정렬 odd_created_at + 상태/처리업체 필터)이 풀스캔 + filesort.\n효과:\n  idx_odd_created          : 기본 목록 정렬 + 날짜범위\n  idx_odd_state_created     : 분석상태(odd_state) 필터 + 정렬\n  idx_odd_provider_created  : 처리업체(odd_provider) 필터 + 정렬\n  idx_odd_tx                : 분석번호(odd_transaction_id) 검색\n적용: 수동 (스테이징/운영 각각 1회). 온라인 DDL(ALGORITHM=INPLACE, LOCK=NONE) 무중단.\n      운영은 저트래픽 시간대 권장. LOCK=NONE 미지원 시 pt-online-schema-change.","hangul_chars":117,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0009_treat_provider_split.sql","lang":"sql","line_start":1,"line_end":4,"block_type":"line","text":"진료 공급자 수집 분할 횟수 컬럼 추가\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\n조회기간(예: 5년)을 N등분해 순차 수집 후 병합한다. 1(기본)이면 분할 없이 1회 호출(기존 동작).\n현재 coocon만 지원. 어드민(진료 공급자 설정)에서 값 조정. idempotent 아님(컬럼 존재 시 에러 → 1회만).","hangul_chars":111,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0010_log_treat_elapsed.sql","lang":"sql","line_start":1,"line_end":4,"block_type":"line","text":"진료 수집 소요시간/타임아웃 기록 컬럼 추가 (분할 효과 측정 + 오래 걸린 실패 집계용)\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\ncodef_elapsed_ms: 2차 수집(내진료정보열람 등) 호출 소요 ms. NULL=미측정(기존/타벤더).\ncodef_timeout: 조회 타임아웃으로 실패했는지(1) 여부. idempotent 아님(컬럼 존재 시 에러 → 1회만).","hangul_chars":113,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0011_order_detail_timeout.sql","lang":"sql","line_start":1,"line_end":4,"block_type":"line","text":"진료 수집 타임아웃 실패 표시 컬럼 (유저 분석목록에서 '인증 재시도' 대신 '건강이음 안내' 구분용)\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\nodd_timeout=1: 수집 조회 타임아웃으로 실패한 건(병력 과다 헤비유저). 재시도해도 또 타임아웃이라\n  목록 문구를 '건강이음 확인'으로 바꾸고 재시도 버튼을 숨긴다. idempotent 아님(컬럼 존재 시 에러 → 1회만).","hangul_chars":139,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0012_treat_setting.sql","lang":"sql","line_start":1,"line_end":5,"block_type":"line","text":"진료 전역 설정 테이블 (key-value). 자동차보험 수집 전체 ON/OFF 등 전역 토글 저장.\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)\nenable_treat_car: '1' 자동차 수집 전체 ON(기본) / '0' OFF. 어드민(진료 공급자 설정)에서 토글.\n  기존 env(ENABLE_TREAT_CAR)를 대체. 운영 중 재배포 없이 즉시 자동차 수집 차단/복구 가능.\nidempotent 아님(테이블 존재 시 에러 → 1회만).","hangul_chars":117,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0012_treat_setting.sql","lang":"sql","line_start":15,"line_end":16,"block_type":"line","text":"prod는 자동차 OFF로 시작(Phase 1 안전). 외부벤더(octover/hyphen/coocon)는 자동차 세션 불가라\n건강만 유지하고, 자동차 토글 ON은 inhouse(자체엔진) 자동차 준비 후에 켠다.","hangul_chars":48,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0013_treat_dropout.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"인증 이탈 클라 비콘 적재 테이블 (2026-07-01)\n프론트가 인증단계에서 유저 이탈(탭닫기/전환) 시 stage+timing을 sendBeacon으로 쏜 것을 기록.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0014_org_tree.sql","lang":"sql","line_start":1,"line_end":4,"block_type":"line","text":"0014_org_tree.sql\n기업 조직트리 계층화(materialized path) + 조직관리자 자격 플래그\ncorp 권한위임 설계: 조직관리자(CORP_ORG)가 자기 org 부분트리만 조회.\n부분트리 필터는 각 도메인 WHERE 에 org_path LIKE '/{orgId}/%' 한 줄로 주입.","hangul_chars":57,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0014_org_tree.sql","lang":"sql","line_start":6,"line_end":6,"block_type":"line","text":"1) 조직트리 계층 컬럼 (인접리스트 parent + materialized path)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0014_org_tree.sql","lang":"sql","line_start":20,"line_end":20,"block_type":"line","text":"2) 조직관리자 자격 플래그","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0014_org_tree.sql","lang":"sql","line_start":24,"line_end":25,"block_type":"line","text":"3) 백필: 기존 조직은 평면(계층 없음)이므로 전부 루트로.\n   루트 = parent NULL, depth 0, path '/{orgId}/' (앞뒤 슬래시로 LIKE prefix 오탐 차단)","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0015_order_settlement_price.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"0015_order_settlement_price.sql\n주문별 기업 정산 기준 금액 저장. 기존 주문은 결제금액 우선, 없으면 상품 판매가로 백필한다.","hangul_chars":37,"class":"1_policy","tags":["1_policy","2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0016_money_charge_request.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"0016_money_charge_request.sql\n기업머니 충전요청: 기업관리자 요청 → 서비스 관리자 승인/반려 → 승인 시 기업머니 적립","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0017_money_actor_audit.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"0017_money_actor_audit.sql\n기업머니/회원지급 행위자 감사추적: 서비스 관리자 adm_id 외 기업/조직관리자 actor 기록","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0018_order_settlement_price_repair.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"0018_order_settlement_price_repair.sql\nord_settlement_price 컬럼 추가 후 구버전 프로세스가 생성한 주문을 보정한다.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0022_money_charge_request_menu.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"기업 충전요청 승인 메뉴 추가. 사이드바는 tn_menu(DB)로 그려지므로 메뉴 행 + 권한매핑이 필요하다.\n기존 기업머니 관리(/money/corp-money)와 같은 부모/depth/권한을 사용한다.","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0023_agency_settlement_confirm.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"후불정산·기업계약 변경안: 과금방식, 정산확정 상태, 주문별 정산반영, 메일 발송 이력.\n기존 행은 default 백필: 계약=POSTPAID(후불), 정산=PENDING(미정산), map=INCLUDE(반영).","hangul_chars":51,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0024_company_terms_defaults.sql","lang":"sql","line_start":1,"line_end":3,"block_type":"line","text":"기업별 약관을 기존 보험유니버스 약관 4종의 타입별 교체값으로 관리한다.\n배포 파이프라인이 SQL을 자동 적용하지 않으므로 환경별로 수동 적용한다.\nunique key 추가 전 운영 적용 시 (agc_id, agt_type), tem_type 중복을 먼저 확인한다.","hangul_chars":76,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0024_company_terms_defaults.sql","lang":"sql","line_start":37,"line_end":37,"block_type":"line","text":"기업별 약관 자동채움용 보험유니버스 기본 약관 4종","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0024_order_billing_type.sql","lang":"sql","line_start":1,"line_end":5,"block_type":"line","text":"0024_order_billing_type.sql\n주문별 과금방식 스냅샷(기획 §3.4) — 주문 생성 시 그 시점 활성계약 act_billing_type 복사.\n정산 집계·기업주문관리 과금방식 표시/필터의 기준(계약이 나중에 바뀌어도 과거 주문은 생성 시점 방식 유지).\n기업FC 주문만 값 보유(PREPAID/POSTPAID/FREE), B2C 주문은 NULL.\n⚠️ 운영/스테이징 DB에 직접 적용해주세요. (배포 파이프라인이 자동 적용하지 않음)","hangul_chars":112,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0024_order_billing_type.sql","lang":"sql","line_start":10,"line_end":10,"block_type":"line","text":"백필: 기업FC 주문 = 주문일이 포함되는 계약(복수면 최신 act_id)의 과금방식, 매칭 계약 없으면 POSTPAID(기존 정책).","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/0024_order_billing_type.sql","lang":"sql","line_start":26,"line_end":31,"block_type":"line","text":"[검증] 기업FC 주문 중 미채움 0건이어야 함\nSELECT COUNT(*) FROM tn_order o\nJOIN tn_payment p ON p.pmt_id = o.pmt_id\nJOIN tn_subscribe s ON s.sub_id = p.sub_id\nJOIN tn_member m ON m.mem_id = s.mem_id AND m.mem_type='MEM002'\nWHERE o.ord_billing_type IS NULL;","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0025_treat_car_canary_request.sql","lang":"sql","line_start":1,"line_end":3,"block_type":"line","text":"자동차 내부 카나리용 1회 요청/동의 영수증.\n배포 파이프라인이 SQL을 자동 적용하지 않으므로 운영 승인 뒤 수동 적용한다.\n빈 테이블로 생성되므로 행을 사전 발급하지 않는 한 자동차 수집은 fail-closed다.","hangul_chars":75,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0026_agency_analysis_view.sql","lang":"sql","line_start":1,"line_end":2,"block_type":"line","text":"기업관리: 분석관리 화면 노출여부 (0: 미노출 | 1: 분석목록만 | 2: 분석목록+상세팝업)\n기업관리자/조직관리자 콘솔의 분석관리 메뉴·상세팝업 노출을 기업 단위로 제어한다. 기본 미노출.","hangul_chars":70,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/0027_loss_analysis.sql","lang":"sql","line_start":46,"line_end":46,"block_type":"line","text":"관리자 구독관리 메뉴: 민감한 실손 원문은 기존 분석로그 관리자 권한만 복사한다.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/relations.ts","lang":"js","line_start":688,"line_end":690,"block_type":"line","text":"============================================================================\n머니 시스템 Relations\n============================================================================","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 2차 수집 호출 소요 ms (측정 벤더만, null=미측정)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":39,"line_end":39,"block_type":"line","text":"* 조회 타임아웃 실패 여부","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":404,"line_end":404,"block_type":"line","text":"분석관리 화면 노출여부 (0: 미노출 | 1: 분석목록만 | 2: 분석목록+상세팝업)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":420,"line_end":421,"block_type":"line","text":"* 기업조직(task-688): 기업↔기업상품 1:N 관계 도입을 위한 조직 단위 식별자.\n*   orgName은 agcId 내 UNIQUE, orgCode는 NULL 허용·NOT NULL일 때만 agcId 내 UNIQUE.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":427,"line_end":427,"block_type":"line","text":"* 조직트리(corp 권한위임): materialized path. 루트=parent NULL, path '/{orgId}/'. FK는 DDL(0014)에서 self-ref.","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":450,"line_end":450,"block_type":"line","text":"* 기업조직(task-688): 마이그레이션 후 NOT NULL ALTER 예정. 신규 등록은 항상 지정.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":460,"line_end":460,"block_type":"line","text":"* 계약 상태(task-688): ACTIVE/EXPIRED/TERMINATED. 마이그레이션으로 기본 'ACTIVE'.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":462,"line_end":462,"block_type":"line","text":"* 정산 수수료율(task-688): 0~100, NULL 허용. 소수점 2자리.","hangul_chars":13,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":464,"line_end":464,"block_type":"line","text":"* 계약 메모(task-688)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":466,"line_end":466,"block_type":"line","text":"* 과금방식(후불정산 변경안): PREPAID/POSTPAID/FREE. PREPAID는 추후 지원.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":468,"line_end":468,"block_type":"line","text":"* 계약 구독계정수 하한(후불정산 변경안). NULL이면 하한 판정 skip.","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":470,"line_end":470,"block_type":"line","text":"* 회계팀 이메일(후불정산 변경안). FREE 계약은 선택.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":516,"line_end":516,"block_type":"line","text":"* 정산상태(후불정산 변경안): PENDING(미정산)/CONFIRMED(정산확정)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":519,"line_end":519,"block_type":"line","text":"* 확정 처리 관리자 id(후불정산 변경안)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":521,"line_end":521,"block_type":"line","text":"* 정산확정금액 스냅샷(후불정산 변경안): 확정 시 INCLUDE 합","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":523,"line_end":523,"block_type":"line","text":"* 세금계산서 발행여부·발행일(후불정산 변경안, 수기 기록)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":538,"line_end":538,"block_type":"line","text":"* 정산반영(후불정산 변경안): INCLUDE(반영)/EXCLUDE(미반영)/CARRYOVER(이월)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":540,"line_end":540,"block_type":"line","text":"* 이월 편입 시 원 정산 id(후불정산 변경안, 중복 청구 추적)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":551,"line_end":551,"block_type":"line","text":"* 후불정산 변경안: 정산 메일 발송 이력","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":555,"line_end":555,"block_type":"line","text":"* 수신자(콤마구분)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":559,"line_end":559,"block_type":"line","text":"* 발송 관리자 id","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1483,"line_end":1483,"block_type":"line","text":"* 기업조직(task-688): 마이그레이션 후 NOT NULL ALTER 예정. 신규 등록 시 항상 지정 필수.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1485,"line_end":1485,"block_type":"line","text":"* 조직관리자 자격(corp 권한위임): 1이면 자기 org_id 부분트리 조회 권한(CORP_ORG)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1614,"line_end":1615,"block_type":"line","text":"* 과금방식 스냅샷(주문 생성 시 활성계약 act_billing_type 복사) — 정산 집계·표시 기준.\n*   기업FC 주문만 값 보유(PREPAID/POSTPAID/FREE), B2C 주문은 NULL.","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1636,"line_end":1636,"block_type":"line","text":"* 진료 처리 공급자 ('codef'|'coocon'|'octover'). 멀티 디스패처가 처리완료 시 기록.","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1644,"line_end":1644,"block_type":"line","text":"* 수집 타임아웃 실패(병력과다) — 목록에서 재시도 대신 건강이음 안내","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1703,"line_end":1703,"block_type":"line","text":"* 기관별 일시 사용중지 설정 (심평원/국세청)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1724,"line_end":1725,"block_type":"line","text":"* 진료 스크래핑 공급자 설정 (멀티 디스패처 풀). 관리자가 단가/한도/사용여부 조정.\n* 디스패처는 enabled=1 행을 unit_cost 오름차순(=싼 곳 우선)으로 읽어 라우팅.","hangul_chars":54,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1730,"line_end":1730,"block_type":"line","text":"* 분당 한도","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1731,"line_end":1731,"block_type":"line","text":"* 플로우 1건당 비용(한도 소모)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1732,"line_end":1732,"block_type":"line","text":"* 단가(낮을수록 우선)","hangul_chars":8,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1733,"line_end":1733,"block_type":"line","text":"* 사용 여부","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1734,"line_end":1734,"block_type":"line","text":"* 분당 rate-limit(타임) 적용 여부 — ON이면 limitPerMin/flowCost를 '분당 허용건수'로 해석","hangul_chars":20,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1735,"line_end":1735,"block_type":"line","text":"* 수집 분할 횟수(조회기간 N등분 순차+병합). 1=분할없음. 현재 coocon만 지원","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1736,"line_end":1736,"block_type":"line","text":"* 표시 정렬","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1737,"line_end":1737,"block_type":"line","text":"* 벤더 장애 통보 웹훅 URL(구글챗 등, 빈 값=미발송). 이 벤더 관련 경고만 이 채널로.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1748,"line_end":1748,"block_type":"line","text":"* 진료 전역 설정(key-value). 자동차보험 수집 전체 ON/OFF(enable_treat_car) 등. env 대체, 어드민에서 토글.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1750,"line_end":1750,"block_type":"line","text":"* 설정 키(enable_treat_car 등)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1751,"line_end":1751,"block_type":"line","text":"* 값('1'/'0' 등 문자열)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1761,"line_end":1762,"block_type":"line","text":"* 자동차 내부 카나리 1회 요청. 행은 운영자가 승인된 동의문과 함께 사전 발급하고,\n* 일반 알림톡 사용자가 그 문구에 명시 동의한 뒤에만 odd_id 1건으로 소비된다.","hangul_chars":60,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1784,"line_end":1785,"block_type":"line","text":"* ★인증 이탈 클라 비콘(2026-07-01): 프론트가 인증단계에서 유저 이탈(탭닫기/전환) 시 stage+timing을\n*   sendBeacon으로 쏜 것을 적재. 서버 퍼널(엔진)이 못 보는 '유저가 언제·어디서 떠났나'를 클라 시점으로 채움.","hangul_chars":66,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1788,"line_end":1788,"block_type":"line","text":"* certify 세션ID(서버 퍼널 조인키)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1789,"line_end":1789,"block_type":"line","text":"* 대리점/초대 코드","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1790,"line_end":1790,"block_type":"line","text":"* 이탈 단계(certify_wait/sms_wait 등)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1791,"line_end":1791,"block_type":"line","text":"* 그 단계에 머문 시간(ms)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1792,"line_end":1792,"block_type":"line","text":"* SMS 발송 후 경과(ms) — 미도착 vs 느림 판별","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":1793,"line_end":1793,"block_type":"line","text":"* 발생 이벤트(pagehide/beforeunload/hidden-timeout)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2287,"line_end":2287,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API 응답 임시 저장 테이블 (정회원)","hangul_chars":23,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2291,"line_end":2291,"block_type":"line","text":"* 조제일자","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2293,"line_end":2293,"block_type":"line","text":"* 처방기관(병원명)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2295,"line_end":2295,"block_type":"line","text":"* 조제기관(약국명)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2297,"line_end":2297,"block_type":"line","text":"* 처방기관 코드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2299,"line_end":2299,"block_type":"line","text":"* 조제기관 코드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2303,"line_end":2303,"block_type":"line","text":"* 총 투약일수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2315,"line_end":2315,"block_type":"line","text":"추천보험관리 백업 테이블 (임시 테이블)","hangul_chars":16,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2409,"line_end":2409,"block_type":"line","text":"투약기준관리 - 대분류 (Category)","hangul_chars":9,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2422,"line_end":2422,"block_type":"line","text":"투약기준관리 - 중분류 (Standard)","hangul_chars":9,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2440,"line_end":2440,"block_type":"line","text":"투약기준관리 백업 테이블 - 대분류","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2452,"line_end":2452,"block_type":"line","text":"투약기준관리 백업 테이블 - 중분류","hangul_chars":14,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2467,"line_end":2469,"block_type":"line","text":"========================================\nB2C 전용 테이블 스키마\n========================================","hangul_chars":8,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2473,"line_end":2473,"block_type":"line","text":"암호화된 이름","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2474,"line_end":2474,"block_type":"line","text":"암호화된 전화번호","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2475,"line_end":2475,"block_type":"line","text":"암호화된 생년월일","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2748,"line_end":2748,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API 응답 임시 저장 테이블 (B2C)","hangul_chars":20,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2763,"line_end":2765,"block_type":"line","text":"============================================================================\n머니 시스템 테이블 (Money System Tables)\n============================================================================","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2767,"line_end":2770,"block_type":"jsdoc","text":"tn_money_issue - 회원머니 적립 배치\n관리자가 일반/기업회원에게 머니 \"적립/적립회수\" 일괄 처리","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2796,"line_end":2798,"block_type":"jsdoc","text":"tn_money_issue_target - 적립 대상 회원","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2814,"line_end":2817,"block_type":"jsdoc","text":"th_money_corp - 기업머니 이력\n기업의 보유머니 변동 이력","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2842,"line_end":2845,"block_type":"jsdoc","text":"tn_money_charge_request - 기업머니 충전요청\n기업관리자가 충전 요청하고 서비스 관리자가 승인/반려한다.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2873,"line_end":2876,"block_type":"jsdoc","text":"tn_money_grant - 기업회원 지급 배치\n기업머니에서 기업회원에게 \"지급/지급회수\"","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2904,"line_end":2906,"block_type":"jsdoc","text":"tn_money_grant_target - 지급 대상 회원","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2922,"line_end":2924,"block_type":"jsdoc","text":"tn_money_payment - 결제 정보","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2953,"line_end":2955,"block_type":"jsdoc","text":"th_money_payment_cancel - 결제취소 이력","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":2973,"line_end":2975,"block_type":"jsdoc","text":"tn_money_refund - 환불 관리","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":3002,"line_end":3005,"block_type":"jsdoc","text":"th_money_wallet - 유저 머니 이력\n사용자가 보는 단순 이력 (1건 = 1이력)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":3024,"line_end":3027,"block_type":"jsdoc","text":"tn_money_source - FIFO 원천\n충전/적립/지급 건별 잔액 추적","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"drizzle/schema.ts","lang":"js","line_start":3053,"line_end":3056,"block_type":"jsdoc","text":"th_money_usage - 사용 상세\nsource 잔액 변동 기록 (FIFO 추적)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":11,"line_end":11,"block_type":"jsdoc","text":"알림톡(AT) | 친구톡 (FT)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":15,"line_end":17,"block_type":"jsdoc","text":"메시지 ID\n테스트 모드의 성공일시, 알림톡 요청실패일시 값 없음","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":21,"line_end":21,"block_type":"jsdoc","text":"포인트 (요청시의 포인트)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":25,"line_end":25,"block_type":"jsdoc","text":"개별전송단가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":29,"line_end":29,"block_type":"jsdoc","text":"전제전송단가","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"정상적으로 요청된 연락처 갯수","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":38,"line_end":38,"block_type":"jsdoc","text":"잘못 요청된 연락처 갯수","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":49,"line_end":49,"block_type":"jsdoc","text":"결과 메세지","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":53,"line_end":53,"block_type":"jsdoc","text":"등록된 카드정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"*---------------------------------  알림톡 발송완료여부  ---------------------------------*/","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":121,"line_end":121,"block_type":"jsdoc","text":"결과 메세지","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":131,"line_end":131,"block_type":"line","text":"*---------------------------------  문자 발송완료여부  ---------------------------------*/","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":166,"line_end":166,"block_type":"jsdoc","text":"결과 메세지","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.dto.ts","lang":"js","line_start":170,"line_end":170,"block_type":"jsdoc","text":"다음페이지 여부","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":1,"line_end":1,"block_type":"jsdoc","text":"알림톡 발송요청","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":3,"line_end":3,"block_type":"jsdoc","text":"템플릿 코드","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":6,"line_end":6,"block_type":"jsdoc","text":"발신자 연락처","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":12,"line_end":12,"block_type":"jsdoc","text":"수신자 연락처","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":15,"line_end":15,"block_type":"jsdoc","text":"수신자 이름","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"알림톡 제목","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":21,"line_end":21,"block_type":"jsdoc","text":"알림톡 내용","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":24,"line_end":24,"block_type":"jsdoc","text":"강조표기형의 타이틀","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":27,"line_end":27,"block_type":"jsdoc","text":"버튼 정보","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":30,"line_end":30,"block_type":"jsdoc","text":"실패시 대체문자 전송기능(Y or N)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"실패시 대체문자 제목","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":36,"line_end":36,"block_type":"jsdoc","text":"실패시 대체문자 내용","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"테스트 모드 적용여부 (Y or N) 기본N","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.interface.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"알림톡 발송완료여부","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"알림톡 발송 요청","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.service.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"local 환경에서는 실제 발송 없이 성공 응답 반환","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* 알림톡 발송완료여부확인","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/aligo/src/aligo.service.ts","lang":"js","line_start":105,"line_end":105,"block_type":"line","text":"* 문자발송완료여부확인","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* 2차 수집(내진료정보열람 등) 호출 소요 ms. 측정 벤더(coocon)만 채움 → 로그 적재.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":29,"line_end":29,"block_type":"line","text":"* 조회 타임아웃으로 실패했는지 여부. 분할 효과/오래걸린 실패 집계용.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"보안문자","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"보안문자새로고침","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"SMS 인증번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":48,"line_end":48,"block_type":"jsdoc","text":"간편인증","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"추가 인증 필요 유무 (true : 추가 인증 필요)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":59,"line_end":59,"block_type":"jsdoc","text":"추가 인증 방식","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":64,"line_end":64,"block_type":"jsdoc","text":"잡 인덱스","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":69,"line_end":69,"block_type":"jsdoc","text":"스레드 인덱스","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":74,"line_end":74,"block_type":"jsdoc","text":"트렌젝션 아이디","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"추가 인증 시간","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":84,"line_end":84,"block_type":"jsdoc","text":"추가인증 정보 Data","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":197,"line_end":197,"block_type":"line","text":"* 진료정보요청후","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":199,"line_end":199,"block_type":"line","text":"* 추가 인증완료후 실패일 시","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":200,"line_end":200,"block_type":"jsdoc","text":"추가 인증 필요 유무 (true : 추가 인증 필요)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":205,"line_end":205,"block_type":"jsdoc","text":"추가 인증 방식","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":210,"line_end":210,"block_type":"jsdoc","text":"잡 인덱스","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":215,"line_end":215,"block_type":"jsdoc","text":"스레드 인덱스","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":220,"line_end":220,"block_type":"jsdoc","text":"트렌젝션 아이디","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":225,"line_end":225,"block_type":"jsdoc","text":"추가 인증 시간","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":230,"line_end":230,"block_type":"jsdoc","text":"추가인증 정보 Data","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":236,"line_end":236,"block_type":"line","text":"* 추가 인증완료후 성공일 시","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":263,"line_end":263,"block_type":"line","text":"* 첫번째 인증요청","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":292,"line_end":292,"block_type":"line","text":"* 진료정보요청후","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":357,"line_end":359,"block_type":"line","text":"* 심평원 다건요청 2차 자료수집 응답 (task-06)\n* data는 요청 배열과 동일 인덱스로 정렬 (index 0=기본, 1=자동차)\n* 1차 인증요청 응답은 공유 twoWayInfo 1세트가 오므로 CertifyResponseDto 형태를 재사용","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":361,"line_end":361,"block_type":"line","text":"* result는 배치 전체에 대한 공유 단일 객체이므로 each:true 미적용 (배열인 data에만 each:true 유지)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":373,"line_end":373,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API - 항목 DTO (task-01)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":375,"line_end":375,"block_type":"jsdoc","text":"조제일자","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":380,"line_end":380,"block_type":"jsdoc","text":"처방기관(병/의원명)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":385,"line_end":385,"block_type":"jsdoc","text":"조제기관(약국명)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":390,"line_end":390,"block_type":"jsdoc","text":"처방기관 코드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":395,"line_end":395,"block_type":"jsdoc","text":"조제기관 코드","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":405,"line_end":405,"block_type":"jsdoc","text":"총 투약일수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":411,"line_end":411,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API - 응답 데이터","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.dto.ts","lang":"js","line_start":413,"line_end":413,"block_type":"jsdoc","text":"추가 인증 필요 유무","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"*추가인증후","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":49,"line_end":50,"block_type":"line","text":"* 심평원 다건요청 - 배열 요소 1건 (기존 단건 파라미터 + 상품 구분자 inquiryType)\n* 공유 인증필드는 전 요소 동일, 2차전용 필드(is2Way/twoWayInfo 등)는 1차 응답의 단일 공유 twoWayInfo를 전 요소에 동일 적용","hangul_chars":61,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":52,"line_end":52,"block_type":"line","text":"* 배열요소 구분자: '0'=기본(진료/상세/처방·투약), '1'=자동차보험 (확장: '2'=내가먹는약)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"* 주문 상관키(ordId 등) — inhouse 엔진 로그 조인용. 외부 벤더(codef/coocon 등)는 무시. PII 아님. optional(하위호환)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":58,"line_end":58,"block_type":"line","text":"* 심평원 다건요청 본문 타입 (요청 배열)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":61,"line_end":61,"block_type":"line","text":"* 국세청 연말정산간소화(의료비) Codef 요청 파라미터","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.interface.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* 2차 자료요청 시 사용","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":19,"line_end":19,"block_type":"line","text":"* 멀티 디스패처 공급자 계약. codef↔coocon 순환참조 방지 위해 type-only import(런타임 제거).","hangul_chars":24,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":32,"line_end":37,"block_type":"jsdoc","text":"심평원 다건요청 - 1차 인증요청\n기본·자동차(확장: 약) 여러 상품을 단일 인증으로 처리하기 위해 배열 1건으로 요청한다.\nis2Way 미포함(1차) → 공유 twoWayInfo 1세트 반환 → CertifyResponseDto 형태로 정규화하여 반환\n(외부 규격 미확정 대비: 응답 data가 배열/단건 어느 형태로 와도 공유 twoWayInfo 1세트를 추출)","hangul_chars":96,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* codef 는 단건(객체)만 받음 — 배열 다건 미지원(CF-09999). 진료(items[0])만 단건 전송.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":53,"line_end":55,"block_type":"line","text":"* 다건 1차 응답: 한 번의 인증으로 여러 상품을 처리하므로 공유 twoWayInfo 1세트가 반환되는 것이 정상이다.\n* 다만 외부 규격이 항목별 twoWayInfo를 반환할 가능성에 대비해, 배열로 올 경우 항목 간 twoWayInfo 차이를 검사한다.\n* (항목별로 다르면 공유 가정이 깨져 자동차(index 1) 2차 추가인증이 기본 twoWayInfo로 발사되어 실패할 수 있음)","hangul_chars":110,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 공유 twoWayInfo 가정이 유효하지 않음 → 자동차 추가인증 불일치 위험을 운영 로그로 노출","hangul_chars":31,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":73,"line_end":73,"block_type":"line","text":"* 단일 공유 인증세션 설계상 index 0의 twoWayInfo를 대표값으로 사용","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":83,"line_end":87,"block_type":"jsdoc","text":"심평원 다건요청 - 2차 자료수집\n1차에서 받은 공유 twoWayInfo를 전 배열요소에 동일 적용(is2Way=true)하여 배열 1건으로 요청한다.\n응답 data는 요청 배열과 동일 인덱스(0=기본, 1=자동차)로 정렬되며 인덱스별로 saveTest 적재","hangul_chars":71,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"* codef 는 단건(객체)만 받음 — 진료(items[0])만 단건 전송. 응답은 아래에서 [item] 배열로 정규화.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":106,"line_end":106,"block_type":"line","text":"* 응답 data를 배열로 정규화 (단건 객체로 올 경우 배열로 감싸 인덱스 정합 유지)","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":112,"line_end":112,"block_type":"line","text":"* 인덱스별 원본 적재 (0=기본 BASIC, 1=자동차 CAR) - 기존 단건 saveTest 의미 보존","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":127,"line_end":127,"block_type":"jsdoc","text":"@deprecated 다건요청(fetchCertifyMultiple)으로 대체됨. 롤백용으로 잔존","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":143,"line_end":143,"block_type":"jsdoc","text":"@deprecated 다건요청(fetchTreatmentMultiple)으로 대체됨. 롤백용으로 잔존","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":166,"line_end":166,"block_type":"jsdoc","text":"@deprecated 다건요청(fetchTreatmentMultiple)으로 대체됨. 롤백용으로 잔존","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":189,"line_end":190,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' API 호출\n* drugUrl 미설정 시 즉시 빈 응답을 반환하여 기존 플로우 영향 없도록 처리","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":224,"line_end":224,"block_type":"line","text":"* saveTest는 의도적 fire-and-forget이나, unhandled rejection 방지를 위해 catch로 로깅 fallback","hangul_chars":14,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":232,"line_end":232,"block_type":"line","text":"* 코드에프 응답(조제건 객체/배열 + resDrugList 중첩)을 내부 평면 계약(resMedicineSummaryList)으로 변환해 반환.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":241,"line_end":245,"block_type":"line","text":"* 심평원 '내가 먹는약 한눈에' 응답 → 내부 평면 리스트 변환.\n* - data: 단건이면 객체, 다건이면 배열 (조제건 단위)\n* - 약품은 각 조제건의 resDrugList 에 중첩 → 약품 1건당 1행, 조제건 정보(조제일/처방기관/조제기관) 부여\n* - 약품이 없는 조제건도 방문이력 보존 위해 1행 생성(약품 필드 null)\n* - 코드에프 응답 필드명을 내부 계약 필드명으로 매핑","hangul_chars":118,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"line","text":"조제일자(YYYYMMDD)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":259,"line_end":259,"block_type":"line","text":"처방기관","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":260,"line_end":260,"block_type":"line","text":"조제기관(약국/제조사명)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":261,"line_end":261,"block_type":"line","text":"코드에프 미제공","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":262,"line_end":262,"block_type":"line","text":"코드에프 미제공","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/codef/src/codef.service.ts","lang":"js","line_start":264,"line_end":264,"block_type":"line","text":"총 투약일수(코드에프 소문자 days)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":13,"line_end":22,"block_type":"jsdoc","text":"쿠콘 스마트 스크래핑 게이트웨이 호출 + 세션/거래번호 관리.\n\n⚠️ 확정 필요 (쿠콘 dev Auth_key 확보 후 실호출로 검증):\n - 요청 봉투 구조: 본 구현은 {Common, InputList:[{Module,Class,Job,Input}]} 가정 (가이드 2.1 공통입력부 기준).\n   개별 Job 샘플(2.3)은 봉투를 생략해 표기되어 있어, 실제 래핑 형태를 dev 응답으로 최종 확인할 것.\n - 응답 봉투: {Common:{Result_cd,SAS_SessionID...}, ResultList:{Output:{ErrorCode,ErrorMessage,Result,CallBackfunc,req}}} 가정.\n   본 파서는 Output 위치(ResultList.Output / ResultList[0].Output / Output / ResultList)를 방어적으로 탐색한다.\n - AES: 간편인증은 smart_gateway_aes.jsp(암호화) 권장. useAes=false(평문)이 기본이며, AES256 세부(모드/IV)는 [참조2] 확인 후 확정.","hangul_chars":146,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":32,"line_end":32,"block_type":"jsdoc","text":"7자리 거래일련번호 채번","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":38,"line_end":44,"block_type":"jsdoc","text":"게이트웨이 1회 호출.\n@param job      개별부 Job (예: '본인인증' | 'OTP' | '내진료정보열람')\n@param input    개별부 Input\n@param session  세션 유지가 필요한 2회차 이후 호출 시 1회차 응답 세션\n@param dsnc     'S' 세션유지 / 'E' 로그아웃(마지막 호출)","hangul_chars":60,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":75,"line_end":75,"block_type":"line","text":"* 봉투: Dsnc/SAS_SessionID/TimeoutRuntime는 Common 밖 최상위 (공식 포스트맨 샘플 기준)","hangul_chars":17,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":79,"line_end":80,"block_type":"line","text":"* Job별 구간 타임아웃 차등: 인증/로그아웃 등 단계는 120초(쿠콘 권고, 통신사 지연 여유 확대),\n*  수집(내진료정보열람 등 무거운 단계)은 300초로 충분히 줘 정상 수집이 끊기지 않게.","hangul_chars":65,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"line","text":"* 스크래핑 세션 타임아웃 300초 — 8000F101 오류 완화 (쿠콘 권고, 디폴트 150초)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":95,"line_end":97,"block_type":"line","text":"* 쿠콘 TimeoutRuntime(300초)보다 30초 길게. 항상 쿠콘이 먼저 8000F101로 끊게 하여\n*  우리(클라이언트)가 끊는 일을 없앤다 → 쿠콘은 '클라이언트가 끊은 미완료'만 과금하므로\n*  우리가 안 끊으면 미완료 과금을 피한다. (쿠콘 회신 기준)","hangul_chars":77,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":105,"line_end":106,"block_type":"line","text":"* 타임아웃/통신실패에도 trSeq(쿠콘 거래일련번호)를 예외에 실어, 상위에서 거래번호로 남긴다.\n*  (예전엔 trSeq가 예외와 함께 소실돼 로그에 jti 세션블롭이 대신 저장되던 문제.)","hangul_chars":64,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":109,"line_end":109,"block_type":"line","text":"* 원본 axios 에러코드/메시지 보존 (ECONNABORTED 등) — 상위에서 '조회 타임아웃' 판정용.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":122,"line_end":125,"block_type":"jsdoc","text":"바이패스: 외부(보상닥터)가 보낸 쿠콘 봉투를 우리 인증키만 주입해 쿠콘 게이트웨이로 그대로 전달.\n Auth_key는 서버 보유값으로 덮어써 외부 미노출. 응답은 쿠콘 원형 그대로 반환(정규화 안 함).","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 우리가 손대는 건 Auth_key(키 미노출)뿐. TimeoutStep/TimeoutRuntime은 호출측(보상닥터) 봉투 그대로 둔다.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":136,"line_end":136,"block_type":"line","text":"* axios만 호출측 TimeoutRuntime보다 30초 길게(우리가 먼저 끊으면 과금) — 미입력 시 쿠콘 디폴트 150초 기준.","hangul_chars":31,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":146,"line_end":146,"block_type":"jsdoc","text":"응답에서 Output/Common을 방어적으로 추출하여 정규화","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"* Output 위치 후보를 순차 탐색 (봉투 형태 미확정 대비)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"line","text":"* 실응답상 SAS_SessionID는 최상위(decoded.SAS_SessionID). Common 안/오탈자(SAS_SessinID)도 방어.","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":185,"line_end":186,"block_type":"line","text":"* AES256-CBC 적용. useAes=false(기본)면 평문 통과.\n* AES 시 본문 전체 JSON을 암호화→base64하여 { Auth_key, Enc_data } 로 전송 ([참조2]).","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":230,"line_end":230,"block_type":"line","text":"* 평문 JSON이면 axios가 객체로 파싱. 문자열로 오면 파싱 시도.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon-auth.service.ts","lang":"js","line_start":242,"line_end":242,"block_type":"jsdoc","text":"AES 키(32byte)/IV(16byte) 로드. utf8 문자열 길이 검증.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":4,"line_end":8,"block_type":"jsdoc","text":"진료내역 스크래핑 공급자 공통 계약.\nCODEF(헥토)·쿠콘이 동일 시그니처를 만족하여 TreatService가 공급자 무관하게 호출한다.\n(provider 스위치: configuration.ts treatProvider)","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":10,"line_end":11,"block_type":"line","text":"* reqQueueId: 대기열 재요청 시 기존 큐 ID. 멀티 디스패처만 사용(만석 시 순번 유지),\n* 단일 공급자 구현체는 무시(optional이라 시그니처 호환).","hangul_chars":45,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":22,"line_end":25,"block_type":"jsdoc","text":"쿠콘 1차(본인인증) 성공 후 2차(OTP→내진료정보열람)까지 이어가기 위해 유지해야 하는 세션 핸들.\nCODEF의 twoWayInfo(jti 등) 자리에 base64(JSON)로 인코딩하여 클라이언트 계약(GetCertifyResponseDto/TreatDto) 변경 없이 왕복시킨다.","hangul_chars":63,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":27,"line_end":27,"block_type":"jsdoc","text":"거래일련번호","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":29,"line_end":29,"block_type":"jsdoc","text":"SS 서버 거래키값 (로그인 성공 후 본거래에 재사용)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":31,"line_end":31,"block_type":"jsdoc","text":"SS 서버 번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"SS 서버 거래번호","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"LBS 서버 번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":37,"line_end":37,"block_type":"jsdoc","text":"API 서버 번호 (로그아웃 등 후속 거래 Common에 필요)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"본인인증 응답의 OTP 콜백 토큰 (Result.req.Input.req)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":41,"line_end":41,"block_type":"jsdoc","text":"인증 유형: 'simple'(간편) | 'mobile'(휴대폰/문자) — 2차 분기에 사용","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"본인인증 응답의 다음 단계 Job (CallBackfunc: 'OTP' | '휴대폰인증_1' | '휴대폰인증_2')","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":47,"line_end":47,"block_type":"jsdoc","text":"쿠콘 공통부(Common) — Dsnc/SAS_SessionID는 Common 밖 최상위 (가이드 샘플·[참조2] 기준)","hangul_chars":19,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":58,"line_end":58,"block_type":"jsdoc","text":"게이트웨이 요청 봉투 (평문 호출 시 본문) — 공식 포스트맨 샘플 기준","hangul_chars":26,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":60,"line_end":60,"block_type":"jsdoc","text":"\"S\": 세션유지, \"E\": 로그아웃(조회완료 후 필수)","hangul_chars":15,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":63,"line_end":63,"block_type":"jsdoc","text":"스크래핑 각 Step 1개당 타임아웃(초). 미입력시 30초 → 무거운 구간이 30초에 끊겨 8000F101 유발 (가이드 1.0.3)","hangul_chars":32,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":65,"line_end":65,"block_type":"jsdoc","text":"공식 샘플 최상위 필드 (기본 \"\")","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":71,"line_end":71,"block_type":"jsdoc","text":"쿠콘 개별부 1건 ({Module,Class,Job,Input}) — InputList 요소","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"게이트웨이 호출 결과 정규화","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":81,"line_end":81,"block_type":"jsdoc","text":"개별부 ErrorCode (\"00000000\" 정상)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":84,"line_end":84,"block_type":"jsdoc","text":"개별부 Result 객체","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":86,"line_end":86,"block_type":"jsdoc","text":"다음 단계 Job 명 (본인인증 응답의 CallBackfunc, 예: \"OTP\")","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":88,"line_end":88,"block_type":"jsdoc","text":"OTP 콜백 토큰","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":90,"line_end":90,"block_type":"jsdoc","text":"응답 Common에서 추출한 세션 (이후 호출에 재사용)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":94,"line_end":97,"block_type":"jsdoc","text":"우리 loginTypeLevel(간편인증 상세구분) → 쿠콘 인증수단 코드.\n(CertiftDto loginTypeLevel 기준: 1카카오/2페이코/3삼성패스/4KB/5PASS/6네이버/7신한/8토스)","hangul_chars":37,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":109,"line_end":109,"block_type":"jsdoc","text":"우리 telecom(0SKT/1KT/2LGU+/3~5알뜰) → 쿠콘 휴대폰인증_통신사(01/02/03/11~13)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.interface.ts","lang":"js","line_start":119,"line_end":119,"block_type":"jsdoc","text":"세션 핸들 ↔ jti 문자열 인코딩 (클라이언트 계약 무변경 목적)","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":8,"line_end":18,"block_type":"jsdoc","text":"쿠콘 '내진료정보열람' 응답(Result) → 내부 Treatment 계약 변환.\n\n쿠콘 Result 구조:\n  { 개인진료정보요약[], 기본진료내역[], 세부진료정보[], 처방조제정보[] }\n내부 계약(CODEF와 동일):\n  Treatment { resBasicTreatList[], resDetailTreatList[], resPrescribeDrugList[] }\n\n필드 매핑은 codef-used.xlsx(실제 저장 필드)와 1:1.\n단, resHospitalCode는 쿠콘 미제공 → undefined.","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":27,"line_end":36,"block_type":"jsdoc","text":"쿠콘 '내진료정보열람(보험종별=2)' 자동차보험 응답 → Treatment(자동차 전용 필드 포함).\ncreateCarTreat→자동차 분석은 진료일수/의료비를 **자동차 전용 필드**(resTreatDate/resMedicalFee)에서 읽는다.\n  - resTreatDate(진료일수)            ← 내원일수\n  - resTotalAmount(청구진료비 총금액)  ← 총진료비 (건강 매퍼가 이미 채움)\n  - resMedicalFee(자동차보험 총진료비) ← 혜택받은금액(보험부담분)\n⚠️ 쿠콘 자동차 응답은 건강과 동일 한글키 구조라 '자동차보험 총진료비' 전용 필드가 없다.\n   혜택받은금액(보험부담)으로 근사한다(octover와 동일). 쿠콘 자동차 실응답으로 검증 후 보정 필요.\n   (자동차는 처방 없음 → resPrescribeDrugList 는 건강 매퍼 결과상 빈 배열)","hangul_chars":194,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"* 건강 공통 필드 재사용","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":43,"line_end":43,"block_type":"line","text":"* 진료일수","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":44,"line_end":44,"block_type":"line","text":"* 자동차보험 총진료비(근사: 보험부담) — 실응답 검증 필요","hangul_chars":22,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.mapper.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 쿠콘 미제공 — CODEF의 resHospitalCode 대응값 없음","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":4,"line_end":9,"block_type":"jsdoc","text":"자료없음(42110000) 처리 검증.\n - 전 구간 0건 → 빈 분석 성공(CF-00000, 빈 리스트)\n - 분할 중 일부 구간만 0건 → 있는 구간은 살리고 성공\n - 진짜 실패(8000F101)는 그대로 실패","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"인증확정 성공","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":54,"line_end":54,"block_type":"line","text":"실패 아님 = errorTreat 안 탐 = 환불 안 됨","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":60,"line_end":60,"block_type":"line","text":"구간1 정상","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"통째로 안 날아감","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":74,"line_end":74,"block_type":"line","text":"실패 유지","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* ── 자동차보험(보험종별=2, inquiryType='1') ──","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":91,"line_end":91,"block_type":"line","text":"자동차(보험종별=2)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"내원일수 → 진료일수","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":98,"line_end":98,"block_type":"line","text":"혜택받은금액 → 자동차보험 총진료비(근사)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.spec.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"총진료비 → 청구진료비 총금액","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":25,"line_end":38,"block_type":"jsdoc","text":"쿠콘 진료내역 공급자 — CODEF(헥토) 대체.\nCodefService와 동일한 2개 메서드(fetchCertifyMultiple / fetchTreatmentMultiple)를 제공하여\nTreatService가 provider 무관하게 호출한다.\n\n인증 2종 모두 지원 (loginType 분기):\n - loginType='5' 간편인증: 본인인증(인증수단=간편사) → OTP → 내진료정보열람\n - loginType='2' 휴대폰(문자)인증: 본인인증(인증수단=MOBILE, 보안문자자동제출=Y)\n     → 휴대폰인증_2(휴대폰_인증번호=SMS) → 내진료정보열람\n     (보안문자 자동제출 실패 시 휴대폰인증_1(보안문자) 폴백)\n\n범위: 건강보험(보험종별=1) + 자동차보험(보험종별=2, inquiryType='1' 요청 시). 약(③)은 미처리.\n2-way 세션은 CODEF의 jti 자리에 base64 인코딩하여 클라이언트 계약(certify/treat) 무변경으로 왕복.","hangul_chars":183,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":49,"line_end":49,"block_type":"jsdoc","text":"1차: 쿠콘 본인인증 요청 → CODEF CertifyResponseDto 형태로 정규화","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":59,"line_end":59,"block_type":"line","text":"* 휴대폰(문자) 본인인증","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 캡차 자동제출(실패 시 2차에서 휴대폰인증_1 폴백)","hangul_chars":19,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":70,"line_end":70,"block_type":"line","text":"* 간편인증","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":92,"line_end":93,"block_type":"line","text":"* 문자(MOBILE): 본인인증만으론 SMS가 발송되지 않음(확인됨). '휴대폰인증_1' 호출 시점에 SMS 발송.\n* 보안문자자동제출=Y라 보안문자는 빈값(\"\")으로 제출. (간편/카카오는 본인인증에서 바로 푸시 발송돼 불필요)","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":108,"line_end":108,"block_type":"line","text":"* SMS 발송 트리거 완료. 세션은 본인인증 세션(SAS_SessionID) 유지.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":111,"line_end":111,"block_type":"line","text":"* 본인인증(+문자는 휴대폰인증_1) 성공 → CODEF 추가인증 대기(CF-03002)로 매핑","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":124,"line_end":124,"block_type":"line","text":"* 세션 핸들을 jti에 인코딩 → 2차(treat)에서 복원","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":126,"line_end":127,"block_type":"line","text":"* 프론트 카운트다운(targetTime = new Date(twoWayTimestamp) + 170s)의 기준시각.\n* 반드시 number(epoch-ms)여야 함 — 문자열이면 new Date(\"17805...\")가 Invalid Date→00:00 즉시만료.","hangul_chars":29,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":154,"line_end":154,"block_type":"jsdoc","text":"2차: (OTP|휴대폰인증) 확정 → 내진료정보열람 → TreatmentMultipleResponseDto(data=[Treatment])","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"* 1차에서 jti에 인코딩한 세션 복원 (SAS_SessionID 등은 전 단계 동일 세션을 계속 사용)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":169,"line_end":170,"block_type":"line","text":"* 인증확정~조회 거래는 세션이 살아있는 동안 진행하고, 끝나면 finally에서 반드시 로그아웃(세션 종료).\n* 벤더 요청: 내진료정보열람 후 마지막 거래로 '로그아웃'을 하지 않으면 세션이 잔존해 문제가 발생.","hangul_chars":77,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":172,"line_end":172,"block_type":"line","text":"* 2-1. 본인인증 확정 단계 (인증유형별 분기)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":174,"line_end":174,"block_type":"line","text":"* 휴대폰인증_2: 사용자가 받은 SMS 인증번호 제출. (휴대폰인증_1은 certify 단계에서 이미 수행 → SMS 발송됨)","hangul_chars":34,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":189,"line_end":189,"block_type":"line","text":"* 간편인증: OTP 확정 (폰 승인 완료 후)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":200,"line_end":204,"block_type":"line","text":"* 2-2. 내진료정보열람 (보험종별=1 건강보험만 / 상병·민감상병 표시). 세션 유지(S) — 종료는 finally 로그아웃에서.\n*   5년치가 무거우면 300초 timeout으로 끊기므로, 공급자 설정(tpr_split_count)에 따라 조회기간을\n*   N등분해 같은 세션으로 순차 호출 후 병합한다. 1(기본)이면 분할 없이 1회(기존 동작).\n*   ※ 고정 분할(처음부터)만 사용 — 동적 재분할(타임아웃 후 쪼개기)은 세션이 죽어 불가(실증 확인).\n*   ※ 5년 완전성이 깨지면 안 되므로 한 구간이라도 실패하면 전체 실패(부분 저장 안 함).","hangul_chars":163,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"* 건강 호출 기본값. 자동차(2)는 아래 자동차 블록에서 덮어써 별도 호출.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":221,"line_end":222,"block_type":"line","text":"* 수집(내진료정보열람) 소요 측정 시작 — 인증확정 이후. 분할이면 구간별 소요를 따로 기록해\n*   '어느 구간이 몇 초/타임아웃인지'를 실패·성공 메시지로 노출한다(분석로그에서 확인).","hangul_chars":70,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":238,"line_end":238,"block_type":"line","text":"* axios 타임아웃 등 — 구간별 소요 + 소요/타임아웃여부를 예외에 실어 상위(handler)가 기록.","hangul_chars":29,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":248,"line_end":252,"block_type":"line","text":"* 42110000 = \"조회결과 없음(거래내역 없음)\" — 스크래핑은 성공, 내역이 0건이라는 의미.\n*   기관 무응답(8000F101=거래취소)과 달리 정상 거래다. 실패로 떨구지 않고\n*   CODEF와 동일하게 '빈 자료'로 취급하고 다음 구간을 계속 수집한다.\n*   (분할이면 이 구간만 0건이고 다른 구간엔 내역이 있을 수 있으므로 전체 실패 금지.\n*    전 구간 0건이면 medResult=null → 매퍼가 빈 Treatment 반환 → 빈 분석 성공.)","hangul_chars":126,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":258,"line_end":258,"block_type":"line","text":"* 한 구간 실패 = 전체 실패. 세션은 finally 로그아웃에서 정리.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":280,"line_end":280,"block_type":"line","text":"* 원본 적재 (CODEF와 동일 의미: BASIC).","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":293,"line_end":294,"block_type":"line","text":"* 자동차보험(보험종별=2) — 요청에 포함되면 같은 세션으로 1회 더 조회(자동차는 데이터가 적어 분할 불필요).\n* 자동차 실패는 건강 성공을 뒤집지 않는 best-effort 정책이다.","hangul_chars":61,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":309,"line_end":309,"block_type":"line","text":"* 자동차 자료없음 = 정상. data[1] 미추가 → TreatService 가 자동차 미저장으로 처리.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":341,"line_end":341,"block_type":"line","text":"* 구간별 소요 노출 (분석로그에서 확인)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":344,"line_end":344,"block_type":"line","text":"* 수집 소요(분할 합산) — 로그 적재용","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":350,"line_end":350,"block_type":"line","text":"* 마지막 거래로 반드시 로그아웃(세션 종료). 성공·실패 무관 수행, 실패해도 본 응답에 영향 없게 best-effort.","hangul_chars":37,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":357,"line_end":359,"block_type":"line","text":"* ── 고정 분할 헬퍼 ──────────────────────────────────────────────\n* 조회기간을 n등분한 [시작,끝] YYYYMMDD 배열. 경계 겹침/누락 0 (구간 끝+1일 = 다음 시작).\n*   기간이 분할수보다 짧으면 분할하지 않는다(1구간).","hangul_chars":53,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":375,"line_end":375,"block_type":"line","text":"* 마지막 구간은 정확히 종료일까지","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":377,"line_end":377,"block_type":"line","text":"* 균등 분할 경계","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":388,"line_end":388,"block_type":"line","text":"* 두 기간 결과 병합 — 진료내역 4개 배열 concat. 기간이 안 겹치게 분할하므로 중복 없음.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":414,"line_end":415,"block_type":"line","text":"* 쿠콘 \"조회 타임아웃\"으로 소켓이 끊긴 경우만 true (axios timeout/연결끊김).\n*   coocon-auth가 예외를 wrap하며 보존한 origCode/origMessage를 함께 검사한다.","hangul_chars":38,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":437,"line_end":437,"block_type":"line","text":"* 실패건도 쿠콘 거래일련번호(trSeq)를 남겨 CS가 쿠콘 콘솔에서 추적 가능하게 한다.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/coocon/src/coocon.service.ts","lang":"js","line_start":439,"line_end":439,"block_type":"line","text":"* 수집 소요(실패까지) — 로그 적재용","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/crypto/src/crypto.service.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"base64 형식인지 hex 형식인지 자동 감지","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/crypto/src/crypto.service.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"안전하게 복호화 시도 (실패 시 원본 반환)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/crypto/src/crypto.service.ts","lang":"js","line_start":51,"line_end":51,"block_type":"line","text":"복호화 실패 시 원본 반환 (이미 평문일 가능성)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/drizzle/src/drizzle.service.ts","lang":"js","line_start":30,"line_end":30,"block_type":"line","text":"* query가 보고싶을 경우 logger : ture","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":9,"line_end":15,"block_type":"jsdoc","text":"하이픈 in0165001213 응답(data) → 내부 Treatment 계약(CODEF/쿠콘/옥토버와 동일 res* 필드).\n - basicMedicalTreatmentInfoList → resBasicTreatList\n - detailedMedicalTreatmentInfoList → resDetailTreatList\n - prescriptionFormulationInfoList → resPrescribeDrugList\n매핑 근거: OpenAPI 스키마(BasicMedicalTreatmentInfo/DetailedMedicalTreatmentInfo/PrescriptionFormulationInfo).","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":25,"line_end":25,"block_type":"line","text":"* '해당없음' 등은 그대로 두되 빈 코드만 정규화","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":31,"line_end":31,"block_type":"line","text":"* 건강보험 등 혜택받은 금액(공단부담)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 내가 낸 의료비(본인부담)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":68,"line_end":76,"block_type":"jsdoc","text":"하이픈 B0003(자동차보험) 응답 → Treatment(자동차 전용 필드 포함).\ncreateCarTreat→자동차 분석은 진료일수/의료비를 **자동차 전용 필드**(resTreatDate/resMedicalFee)에서 읽는다.\n  - resTreatDate(진료일수)            ← numberVisitDays\n  - resTotalAmount(청구진료비 총금액)  ← totalMedicalExpenses (건강 매퍼가 이미 채움)\n  - resMedicalFee(자동차보험 총진료비) ← medicalExpensesIPaid (B0003에서 자동차보험 총진료비)\nhyphen은 octover와 달리 자동차보험 총진료비 전용 필드가 있어 정확히 매핑된다.\n자동차는 처방 없음 → resPrescribeDrugList 는 빈 배열.","hangul_chars":125,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* 건강 공통 필드(상병/병원/총액/세부) 재사용","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":82,"line_end":82,"block_type":"line","text":"* 진료일수","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.mapper.ts","lang":"js","line_start":83,"line_end":83,"block_type":"line","text":"* 자동차보험 총진료비","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":4,"line_end":8,"block_type":"jsdoc","text":"hyphen 자동차보험(B0003 별도 호출) 분기 검증.\n - 건강(B0002)+자동차(B0003) 성공 / 자동차 자료없음(성공) / 자동차 수집실패(전체실패) / 미요청 / 건강실패 / 세션복원실패.\nhttp.post 를 목으로 하이픈 응답을 시뮬레이션(실호출 X).","hangul_chars":71,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":16,"line_end":16,"block_type":"line","text":"* 기본: 분할 없음(기존 동작)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":45,"line_end":45,"block_type":"line","text":"* svcKey: 'outB0002'(건강) | 'outB0003'(자동차)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"* numberVisitDays → 진료일수","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* medicalExpensesIPaid → 자동차보험 총진료비(정확)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":65,"line_end":65,"block_type":"line","text":"* totalMedicalExpenses → 청구진료비 총금액","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 분할 응답: out에 갱신 cookieData를 실어 구간 간 체이닝 검증용.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":128,"line_end":128,"block_type":"line","text":"* 1구간 응답: 갱신 세션키 CK1","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 2구간 응답","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":134,"line_end":135,"block_type":"line","text":"* 건강만 2분할(자동차 없음)\n* 병합: 두 구간 basic 1건씩 → 2건","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 구간 간 cookieData 체이닝: 1구간은 1차 세션값(CK), 2구간은 1구간 응답값(CK1)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.spec.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"* 구간별 기간 오버라이드(sdate/edate) 적용 — 경계 누락 없이 연속","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":32,"line_end":32,"block_type":"jsdoc","text":"unwrap 결과 — 봉투(out/outB0002) 무관하게 정규화","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":42,"line_end":52,"block_type":"jsdoc","text":"하이픈/인포텍(InfoTech) 진료내역 공급자 — CODEF/쿠콘/옥토버와 동일 TreatScraper 구현.\nTreatService 가 provider 무관하게 호출(treatProvider='hyphen').\n\n인증 2종 (base.loginType):\n - '5' 간편(EASY): 1차 요청(앱푸시) → step_data → 2차 step_data 재전송 → 진료내역\n - '2' 휴대폰(SMS): 1차 captchaPass(보안문자 자동통과+SMS발송) → userData → 2차 identityCheck + step_input(SMS코드) + userData\n\n통신: POST apigw.infotech.co.kr/api/service, 헤더 api-cloud-key, 바디 appCd/orgCd:hira/svcCd:B0002 (평문, 암호화 없음).\n2-step 세션(step_data|userData)은 CODEF jti 자리에 base64 인코딩하여 클라 계약 무변경 왕복.","hangul_chars":99,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"jsdoc","text":"1차: 인증요청 → CODEF CertifyResponseDto(CF-03002) 정규화","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":72,"line_end":73,"block_type":"line","text":"* 하이픈 추적키(reqCd) — 우리가 발급해 요청에 실어 보내고, 결과 transactionId에도 남겨 CS가 추적 가능하게 한다.\n* (하이픈은 응답에 거래번호를 주지 않으므로 이 reqCd가 유일한 추적키다.)","hangul_chars":62,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* 통신/업무 오류 또는 2step 세션 미수신 → 실패","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":89,"line_end":89,"block_type":"line","text":"* 1차 reqCd를 세션에 실어 2차까지 동일 유지 → 주문 분석번호(oddTransactionId)와 2차 로그 거래번호가 일치(조인 정합).","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":107,"line_end":115,"block_type":"jsdoc","text":"2차: 세션 재전송 → 진료내역 수집 → TreatmentMultipleResponseDto(data=[건강, 자동차]).\n - 건강(B0002)은 필수. 실패 시 전체 실패.\n - 자동차(B0003)는 요청 배열에 inquiryType='1'이 있을 때만 별도 호출(svcCd만 다름, 세션 재사용).\n   정책(octover와 통일): 자동차 '수집 실패'는 전체 실패. '자료없음'은 errYn=N 빈 data → 빈 성공이라\n   전체 실패로 보지 않는다.\n   ⚠️ 자동차 호출도 1차 세션(step_data/userData)을 재전송한다. SMS step_input(인증번호) 1회성 등\n      세션 재사용 가능 여부는 stg 실호출로 검증 필요(검증 전까지 자동차 실패는 정책상 전체 실패).","hangul_chars":151,"class":"1_policy","tags":["1_policy","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":130,"line_end":131,"block_type":"line","text":"* 2차 추적키(reqCd) — 1차에서 세션에 실어둔 값을 재사용해 1·2차 동일하게 유지(주문 분석번호=로그 거래번호 정합).\n*  (구 세션 호환: reqCd 없으면 새로 채번)","hangul_chars":52,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":134,"line_end":138,"block_type":"line","text":"* 건강보험(B0002) — 필수. 공급자 설정(tpr_split_count)에 따라 조회기간을 N등분해 같은 세션으로\n*   순차 수집 후 병합한다. 1(기본)이면 분할 없이 1회(기존 동작과 동일).\n*   ⚠️ cookieData(세션키)는 조회마다 갱신되므로 구간 간 체이닝한다(직전 구간 응답 cookieData →\n*      다음 구간 요청 세션에 주입) → 세션종료(I0001-010)/'이미 완료된 요청' 회피. 첫 구간은 1차 세션값.\n*   ⚠️ 5년 완전성: 한 구간이라도 실패하면 즉시 전체 실패(부분 저장 안 함).","hangul_chars":138,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":151,"line_end":151,"block_type":"line","text":"* 구간 간 체이닝되는 세션키 — 첫 구간은 1차 세션값, 이후는 직전 구간 응답값.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":158,"line_end":158,"block_type":"line","text":"* 한 구간 실패 = 전체 실패","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":162,"line_end":162,"block_type":"line","text":"* 갱신된 세션키를 다음 구간(또는 자동차 B0003)에 넘긴다.","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 자동차보험(B0003) — 요청에 포함된 경우에만 별도 호출(전체 기간 1회, 분할 안 함).","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":169,"line_end":170,"block_type":"line","text":"* 건강(B0002) 마지막 구간에서 갱신된 cookieData를 자동차(B0003) 세션에 주입 — 세션 종료(I0001-010) 회피.\n* (1차 세션 단순 재사용 시 B0002가 세션을 소진해 B0003에서 '이미 완료된 요청'이 났음)","hangul_chars":55,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":179,"line_end":179,"block_type":"line","text":"* 정책(octover와 통일): 자동차 수집 실패는 전체 실패. 자료없음은 ok=true 빈값이라 여기로 오지 않음.","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":201,"line_end":204,"block_type":"jsdoc","text":"단일 서비스(B0002 건강 / B0003 자동차) 2차 수집 — 세션 재전송 → 매핑된 Treatment.\n자료없음(errYn=N 빈 data)은 ok=true(빈 Treatment). 진짜 실패는 ok=false + failResult.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":213,"line_end":213,"block_type":"line","text":"* 조회기간 오버라이드(분할 수집). 미지정 시 base.startDate/endDate(전체 기간).","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":222,"line_end":222,"block_type":"line","text":"* SMS: 인증번호 + 1차 세션(userData) 재전송 (step=identityCheck)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":226,"line_end":226,"block_type":"line","text":"* 간편: step_data 재전송","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":230,"line_end":232,"block_type":"line","text":"* 조회마다 갱신되는 세션키(cookieData)를 응답으로 받는다(showCookie=Y). 다음 호출(자동차 B0003)에\n* 이 값을 넘겨야 '이미 완료된 요청/세션 종료(I0001-010)'를 피한다 — hyphen은 1차 세션 단순 재사용이\n* 아니라 조회마다 cookieData 갱신이 필요(서비스정의서).","hangul_chars":76,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":237,"line_end":239,"block_type":"line","text":"* 하이픈은 진료내역 0건이면 errYn=N(정상)으로 빈 data 를 주고, 매퍼가 빈 Treatment 를\n*   만들어 성공이 된다(자료없음 = 이미 정상 처리). 별도 자료없음 코드 분기 불필요.\n*   (B000x-L01='세션없음', B000x-999='처리중 오류'는 진짜 실패라 그대로 errYn=Y 로 떨군다.)","hangul_chars":77,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":251,"line_end":251,"block_type":"line","text":"* 자동차(CAR)는 진료일수/자동차보험총진료비를 자동차 전용 필드로 채우는 매퍼 사용","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":268,"line_end":268,"block_type":"jsdoc","text":"1·2차 공통 요청 바디(공통부 + 항목). 2차 세션값은 호출측에서 덧붙임.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":275,"line_end":275,"block_type":"line","text":"* 조회기간 오버라이드(분할 수집). 미지정 시 base.startDate/endDate.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":285,"line_end":286,"block_type":"line","text":"* 실행 타임아웃(초) — 인포텍 세션 유지시간을 명시(자료 과다 B0002-999 완화).\n*   axios(330s)보다 작게 둬 응답 왕복 여유. 미설정 시 300초(5분).","hangul_chars":42,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":295,"line_end":295,"block_type":"line","text":"* 상병/민감상병 표시 (CODEF diseaseGubun='1'/sensitiveGubun 대응)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":301,"line_end":304,"block_type":"line","text":"* SMS: 통신사 + 단계별 step\n*  - 1차(certify): 보안문자 자동통과 + SMS 발송(captchaPass)\n*  - 2차(treat)  : 수신 인증번호 확인(identityCheck, step_input=SMS코드)\n* ⚠️ captchaPass 자동통과 실패 시 수동 보안문자(captcha→step_input) 폴백 — 실호출 검증 필요","hangul_chars":50,"class":"2_rationale","tags":["2_rationale","4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":308,"line_end":308,"block_type":"line","text":"* 간편: 인증매체","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":315,"line_end":315,"block_type":"jsdoc","text":"봉투(out/outB0002) 무관 정규화 — step_data/userData/에러/데이터 추출","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":331,"line_end":331,"block_type":"jsdoc","text":"서버간 통신처리 실패 여부 (resCd 가 있고 0000 아님)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":336,"line_end":340,"block_type":"jsdoc","text":"하이픈 실패코드 결정 — 포장코드(CF-99999) 대신 진짜 벤더코드를 결과 code로 노출한다.\n - 하이픈 업무에러는 코드를 errMsg 맨 앞 대괄호([B0002-999], [I0001-V01] 등)에만 담아 보낸다 → 이를 끌어올린다.\n - 통신단 resCd(0000 외, K001/V00x 등)가 있으면 그것을, 둘 다 없을 때만 'CF-99999' 폴백.","hangul_chars":80,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":373,"line_end":373,"block_type":"line","text":"* 타임아웃/네트워크 예외에도 reqCd를 실어, 상위(event-handler)에서 거래번호로 남긴다.","hangul_chars":27,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":375,"line_end":375,"block_type":"line","text":"* 조회 타임아웃(소켓끊김) 감지 — 상위(handler)에서 '병력 과다' 안내 분기용.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":384,"line_end":386,"block_type":"line","text":"* ── 고정 분할 헬퍼 (coocon과 동일 로직) ──────────────────────────\n* 조회기간을 n등분한 [시작,끝] YYYYMMDD 배열. 경계 겹침/누락 0 (구간 끝+1일 = 다음 시작).\n*   기간이 분할수보다 짧으면 분할하지 않는다(1구간).","hangul_chars":58,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":398,"line_end":398,"block_type":"line","text":"* 마지막 구간은 정확히 종료일까지","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":400,"line_end":400,"block_type":"line","text":"* 균등 분할 경계","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.service.ts","lang":"js","line_start":411,"line_end":411,"block_type":"line","text":"* 두 구간 Treatment 병합 — 진료내역 3개 배열 concat. 기간이 안 겹치게 분할하므로 중복 없음.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":1,"line_end":14,"block_type":"jsdoc","text":"하이픈/인포텍(InfoTech) 건강보험심사평가원 '내 진료정보 조회'(svcCd=B0002) 타입/상수.\n스펙 출처: InfoTech_API_공통가이드.xlsx / InfoTech_건강보험심사평가원_서비스정의서.xlsx (정식 연동문서).\n\n통신규격:\n  POST https://apigw.infotech.co.kr/api/service\n  Header: Content-Type=application/json;charset=UTF-8, api-cloud-key=<발급키>\n  Body  : { appCd, orgCd:'hira', svcCd:'B0002', loginMethod, ssn1, ssn2, ... } (평문, 암호화 없음)\n\n2-step 인증:\n  - 간편(EASY): 1차 요청(앱푸시) → 응답 step_data → 2차 step_data 재전송 → 진료내역\n  - 휴대폰(SMS): 1차 captchaPass(보안문자 자동통과·SMS발송) → 응답 userData → 2차 identityCheck + step_input(SMS코드) + userData\n  세션(step_data|userData)을 CODEF jti 자리에 base64 인코딩하여 클라 계약 무변경 왕복.","hangul_chars":129,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":16,"line_end":16,"block_type":"jsdoc","text":"인포텍 API 게이트웨이 (전체 URL — 경로 추가 없음)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":19,"line_end":19,"block_type":"jsdoc","text":"기관코드 / 서비스코드 (서비스정의서)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":21,"line_end":21,"block_type":"line","text":"* 내 진료정보 조회(건강보험)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":22,"line_end":22,"block_type":"line","text":"* 내 진료정보 조회(자동차보험)","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":23,"line_end":23,"block_type":"jsdoc","text":"out 컨테이너 키 (out + svcCd)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":27,"line_end":27,"block_type":"jsdoc","text":"서버간 통신처리 정상코드 (resCd)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":30,"line_end":34,"block_type":"jsdoc","text":"우리 loginTypeLevel(간편인증 상세구분) → 인포텍 step(인증매체).\n(우리: 1카카오/2페이코/3삼성패스/4KB/5PASS/6네이버/7신한/8토스)\n(인포텍 step: kakao/kb/kica(삼성패스)/pass/payco/naver/shinhan/toss/banksalad/nh/hana)","hangul_chars":43,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":46,"line_end":49,"block_type":"jsdoc","text":"우리 telecom(0SKT/1KT/2LGU+/3~5알뜰) → 인포텍 mobileCo.\n(인포텍: SK(SKT)/SM(SK알뜰)/KT(KT)/KM(KT알뜰)/LG(LGU+)/LM(LG알뜰))","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":59,"line_end":59,"block_type":"jsdoc","text":"인포텍 /api/service 요청 바디 (공통부 + B0002 업무항목, 평문)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":61,"line_end":61,"block_type":"jsdoc","text":"어플리케이션코드 (●) — 업체명-api","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":63,"line_end":63,"block_type":"jsdoc","text":"기관코드 (●) — 'hira'","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":65,"line_end":65,"block_type":"jsdoc","text":"서비스코드 (●) — 'B0002'","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":67,"line_end":67,"block_type":"jsdoc","text":"요청고유구분값 (결과 추적용, 선택)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":69,"line_end":69,"block_type":"jsdoc","text":"EndUser 구분값 (선택)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":71,"line_end":75,"block_type":"jsdoc","text":"실행 타임아웃(초) — 인포텍 게이트웨이가 세션을 유지하는 최대 시간.\n문서 미기재 히든 파라미터(인포텍 메일 안내). 미전송 시 인포텍 기본값 적용.\n자료 과다 유저의 수집 조기종료([B0002-999]) 완화용으로 명시 전송한다.","hangul_chars":81,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":77,"line_end":77,"block_type":"jsdoc","text":"CERT(공동인증서) | ID(아이디) | EASY(간편인증) | SMS(휴대폰SMS)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"주민번호 앞 6자리","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":81,"line_end":81,"block_type":"jsdoc","text":"주민번호 뒤 7자리 (평문)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":83,"line_end":83,"block_type":"jsdoc","text":"조회시작일 YYYYMMDD","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":85,"line_end":85,"block_type":"jsdoc","text":"조회종료일 YYYYMMDD","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":87,"line_end":87,"block_type":"jsdoc","text":"인증매체 (간편: kakao/... | SMS: captcha/captchaPass/identityCheck)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":89,"line_end":89,"block_type":"jsdoc","text":"사용자 이름","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":91,"line_end":91,"block_type":"jsdoc","text":"사용자 휴대폰번호","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":93,"line_end":93,"block_type":"jsdoc","text":"사용자 휴대폰통신사 (SMS: SK/SM/KT/KM/LG/LM)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":95,"line_end":95,"block_type":"jsdoc","text":"세션인증값 — 간편 2step 재요청 시 1차 응답값","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":97,"line_end":97,"block_type":"jsdoc","text":"인증단계 입력값 — SMS: 보안문자 또는 SMS인증번호","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":99,"line_end":99,"block_type":"jsdoc","text":"인증단계 사용데이터 — SMS: 1차 응답 userData 재전송","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":101,"line_end":101,"block_type":"jsdoc","text":"상병항목 표시 (Y/N, 기본 N)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":103,"line_end":103,"block_type":"jsdoc","text":"민감상병 표시 (Y/N, 기본 N)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":105,"line_end":105,"block_type":"jsdoc","text":"세션정보 요청 (Y: 응답 cookieData 리턴)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":107,"line_end":107,"block_type":"jsdoc","text":"세션정보 입력 (재사용)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":111,"line_end":111,"block_type":"jsdoc","text":"기본진료내역 1건","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* 진료시작일","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"* 병.의원&약국","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":116,"line_end":116,"block_type":"line","text":"* 입원/외래","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":117,"line_end":117,"block_type":"line","text":"* 주상병코드 (diseaseItemYn=Y)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":118,"line_end":118,"block_type":"line","text":"* 주상병명 (diseaseItemYn=Y)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":119,"line_end":119,"block_type":"line","text":"* 내원일수(B0002) / 진료일수(B0003 자동차)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"* 총 진료비(B0002) / 청구진료비 총금액(B0003 자동차)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":121,"line_end":121,"block_type":"line","text":"* 건강보험 등 혜택받은 금액","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":122,"line_end":122,"block_type":"line","text":"* 내가 낸 의료비(B0002) / 자동차보험 총진료비(B0003 자동차)","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":125,"line_end":125,"block_type":"jsdoc","text":"세부진료정보 1건","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 진료내역","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":131,"line_end":131,"block_type":"line","text":"* 1회 투약량","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":132,"line_end":132,"block_type":"line","text":"* 1일 투여횟수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":133,"line_end":133,"block_type":"line","text":"* 총 투약일수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":136,"line_end":136,"block_type":"jsdoc","text":"처방조제정보 1건","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":140,"line_end":140,"block_type":"line","text":"* 처방/조제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":148,"line_end":148,"block_type":"jsdoc","text":"outB0002 업무 결과 컨테이너","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"* 개인진료정보요약 (현재 계약 미사용)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":158,"line_end":158,"block_type":"jsdoc","text":"out 컨테이너 (공통가이드 'out' = 서비스정의서 응답 객체)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":163,"line_end":163,"block_type":"jsdoc","text":"간편 2step 세션","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":165,"line_end":165,"block_type":"jsdoc","text":"SMS 2step 세션(쿠키 블롭)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":167,"line_end":167,"block_type":"jsdoc","text":"세션유지 쿠키","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":169,"line_end":169,"block_type":"jsdoc","text":"업무 결과 (out + svcCd)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"* 건강보험","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":171,"line_end":171,"block_type":"line","text":"* 자동차보험","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":175,"line_end":175,"block_type":"jsdoc","text":"/api/service 응답 봉투 (공통부)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":177,"line_end":177,"block_type":"jsdoc","text":"서버간 통신처리결과 (0000 정상, K001/K002/V00x/E9xx 오류)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":182,"line_end":182,"block_type":"jsdoc","text":"업무 출력 컨테이너","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":184,"line_end":184,"block_type":"line","text":"* (일부 응답은 out 래핑 없이 평탄화될 수 있어 최상위도 허용)","hangul_chars":22,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":192,"line_end":195,"block_type":"jsdoc","text":"1차(인증요청) 성공 후 2차까지 유지할 세션 핸들.\nCODEF twoWayInfo(jti) 자리에 base64(JSON) 인코딩하여 왕복.","hangul_chars":28,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":197,"line_end":197,"block_type":"jsdoc","text":"간편(EASY) 세션값","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":199,"line_end":199,"block_type":"jsdoc","text":"SMS 세션(쿠키 블롭)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":201,"line_end":201,"block_type":"jsdoc","text":"세션유지 쿠키","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/hyphen/src/hyphen.types.ts","lang":"js","line_start":205,"line_end":205,"block_type":"jsdoc","text":"하이픈 추적키(reqCd) — 1차에서 채번해 2차까지 동일하게 유지(주문 분석번호=로그 거래번호 정합).","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.module.ts","lang":"js","line_start":6,"line_end":9,"block_type":"jsdoc","text":"자체 스크래퍼 엔진 공급자 모듈 — 다른 벤더(codef/coocon/octover/hyphen)와 동일 패턴.\nTreatModule을 import하지 않아 순환의존 없음(forwardRef 불필요).","hangul_chars":36,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":4,"line_end":10,"block_type":"jsdoc","text":"자동차보험(diagAuto) 진료 매핑 회귀 테스트.\n엔진은 진료일수=resVisitDays, 자동차보험총진료비=resPublicCharge로 내보내지만,\ncreateCarTreat는 resTreatDate/resMedicalFee를 읽는다. normalizeTreatment의 자동차 전용\nalias(isAuto=true)가 그 간극을 메우는지, 건강(isAuto=false)엔 안 새는지 검증한다.\n매핑 표준은 octover/hyphen/coocon 3벤더와 동일(진료일수=resTreatDate, 자동차보험총진료비=resMedicalFee).","hangul_chars":90,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"진료일수 (3벤더: 내원일수/numberVisitDays)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"자동차보험총진료비 (3벤더: 혜택받은금액/medicalExpensesIPaid)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":36,"line_end":36,"block_type":"line","text":"청구진료비","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"원본 필드도 유지","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.spec.ts","lang":"js","line_start":66,"line_end":66,"block_type":"line","text":"건강 필드는 그대로","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":25,"line_end":35,"block_type":"jsdoc","text":"자체 스크래퍼 엔진(scraper-engine) 공급자 — CODEF/쿠콘/옥토버와 동일 TreatScraper 구현.\n외부 벤더 API 대신 우리 엔진의 HTTP API를 호출하는 어댑터다(코드는 그냥 5번째 벤더).\n\n 1차 fetchCertifyMultiple → 엔진 POST /api/certify (브라우저 인증, sessionId 발급)\n 2차 fetchTreatmentMultiple → 엔진 POST /api/treat (SMS 확정 + .do HTTP 수집)\n\n독립성: 엔진 측 인프라/용량/기관 오류(BUSY·SYSTEM·VENDOR·NETWORK)는 throw하여\n  디스패처가 기존 벤더로 폴백하게 한다 → inhouse가 죽어도 진료조회는 안 죽는다(블렌드).\n기본 OFF: 공급자 풀(tn_treat_provider/TREAT_POOL)에 'inhouse'가 없으면 호출되지 않는다.","hangul_chars":136,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":45,"line_end":45,"block_type":"jsdoc","text":"1차: 엔진 본인인증 → CODEF CertifyResponseDto(CF-03002) 정규화.","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":56,"line_end":56,"block_type":"line","text":"* certify는 응답 헤더(Set-Cookie)에서 ALB sticky 쿠키를 거둬야 하므로 헤더포함 호출을 쓴다.","hangul_chars":25,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":63,"line_end":63,"block_type":"line","text":"TODO: insuniverse telecom('0'~'5') ↔ 엔진 형식 매핑 — 카나리 실인증에서 확정","hangul_chars":16,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"주문 상관키 — 엔진 로그에 trace=로 찍혀 sessionId↔주문 조인","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":68,"line_end":68,"block_type":"line","text":"* 조인키 1줄: 이 주문(trace)이 엔진의 어느 sessionId로 갔는지 + 1차 결과. 시각 추론 없이 박스로그와 결합.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":73,"line_end":74,"block_type":"line","text":"* ALB 뒤 멀티박스: certify가 만든 박스로 treat을 보내려고 AWSALB* 쿠키를 세션에 실어 jti로 왕복.\n*   단일박스/스티키 미사용이면 헤더가 없어 undefined → 평소대로 동작(하위호환). 쿠키 값은 로깅 X.","hangul_chars":60,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"인프라/용량/기관 오류 → throw로 디스패처 폴백(블렌드). 유저측 오류 → 그대로 반환.","hangul_chars":29,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":107,"line_end":107,"block_type":"jsdoc","text":"2차: SMS 확정 + 수집 → TreatmentMultipleResponseDto(data=[Treatment...]).","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":128,"line_end":129,"block_type":"line","text":"* certify가 거둔 ALB sticky 쿠키가 있으면 같은 박스로 라우팅되도록 Cookie 헤더로 복원해 보낸다.\n*   없으면(단일박스/스티키 미사용) 헤더 없이 평소대로 호출(하위호환). 쿠키 값은 로깅 X.","hangul_chars":62,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":146,"line_end":146,"block_type":"line","text":"주문 상관키 — 엔진 [treat] 로그에 trace=로","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"* 2차 결과 조인키: 이 주문(trace/oddId)이 어느 session으로 무엇을 수집했는지 + 결과코드.","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":156,"line_end":157,"block_type":"line","text":"자료없음(INH-3001 NO_DATA)은 '실패'가 아니라 '빈 분석 성공'으로 처리한다 —\n  octover/coocon 등 다른 벤더 정책과 동일(환불 X). 실패로 떨어뜨리면 안 됨.","hangul_chars":44,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":169,"line_end":170,"block_type":"line","text":"성공 또는 자료없음 → CF-00000. 각 inquiryType 산출물을 순서대로(CODEF byte-호환).\n  자료없음이면 엔진 data가 비거나 undefined일 수 있어 빈 Treatment로 채운다(빈 분석 성공).","hangul_chars":45,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":180,"line_end":183,"block_type":"line","text":"* 정규화 필수: 보유 treatRepository.create()는 각 필드에 .trim()/.replace()를\n*   무가드 호출한다. 엔진 raw 레코드에 null/undefined/숫자가 하나라도 섞이면\n*   INSERT 전체가 throw → .catch에서 주문이 ODD004(인증실패)로 떨어진다.\n*   octover(mapOctoverToTreatment)·codef와 동일하게 어댑터에서 안전 문자열로 강제한다.","hangul_chars":73,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":188,"line_end":188,"block_type":"line","text":"* 자동차만 자동차 전용 alias 적용(3벤더 octover/hyphen/coocon과 동일 패턴)","hangul_chars":18,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":205,"line_end":210,"block_type":"jsdoc","text":"엔진 raw 진료 데이터를 보유 create() 계약(전 필드 문자열)으로 정규화한다.\n  - null/undefined/숫자 → 안전 문자열(빈 진료 레코드 1건도 INSERT를 깨지 않게).\n  - 키 철자는 create()가 읽는 그대로 맞춘다(특히 resTotalDosingdays 소문자 d).\n  - 약(medicine 등) 다른 형태의 산출물은 건드리지 않고 그대로 통과.","hangul_chars":85,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":219,"line_end":219,"block_type":"line","text":"진료 형태가 아니면(약 요약 등) 그대로","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":225,"line_end":225,"block_type":"line","text":"* 키 철자 흔들림(대문자 D) 방어 — create()는 소문자 d만 읽는다.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":234,"line_end":234,"block_type":"line","text":"* '$'/'해당없음' 더미값은 빈값으로(octover 매퍼와 동일).","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":243,"line_end":245,"block_type":"line","text":"* 자동차 전용 alias(3벤더 octover/hyphen/coocon과 동일 표준) — createCarTreat는 진료일수=resTreatDate,\n*   자동차보험총진료비=resMedicalFee로 읽는다(treat.repository.ts:368·370). 엔진은 그 둘을\n*   resVisitDays/resPublicCharge로 내보내므로 별칭으로 메운다. 건강(isAuto=false)엔 넣지 않아 청결.","hangul_chars":58,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":281,"line_end":281,"block_type":"line","text":"* 공통 요청 헤더(Content-Type + 선택적 x-api-key)에 호출별 extraHeaders(예: Cookie)를 합친다.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":303,"line_end":303,"block_type":"line","text":"연결 실패 = 디스패처 폴백","hangul_chars":10,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":307,"line_end":308,"block_type":"line","text":"* 클라 이탈 비콘을 엔진 대시보드로 포워드(B, 2026-07-01). 엔진이 이 sessionId 세션 타임라인에\n*   '클라 이탈: sms_wait 3초' 를 찍는다. best-effort — 실패해도 무시(이탈은 이미 tn_treat_dropout에 적재됨).","hangul_chars":52,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":325,"line_end":325,"block_type":"line","text":"* 관측(2026-07-01 B 디버깅) — 포워드 도달 확인(axios는 non-2xx면 throw이므로 resolve=성공).","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":330,"line_end":330,"block_type":"line","text":"* best-effort지만 왜 실패했는지는 남긴다(엔진 미도달/URL/타임아웃/4xx 구분).","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":358,"line_end":358,"block_type":"jsdoc","text":"스테이징 국세청 의료비 화면용 엔진 중계. 엔진 키는 브라우저에 노출하지 않는다.","hangul_chars":33,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":366,"line_end":366,"block_type":"line","text":"* post와 동일하되 응답 본문+헤더를 함께 받는다(certify의 Set-Cookie 캡처용).","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.service.ts","lang":"js","line_start":379,"line_end":379,"block_type":"line","text":"연결 실패 = 디스패처 폴백","hangul_chars":10,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":1,"line_end":7,"block_type":"jsdoc","text":"inhouse(자체 스크래퍼 엔진) 어댑터 타입.\n\n엔진(scraper-engine)의 HTTP API(`POST /api/certify`, `POST /api/treat`)를 호출해\nCODEF/쿠콘/옥토버와 동일한 TreatScraper 계약으로 정규화한다.\n2-way 세션(엔진 sessionId)은 CODEF jti 자리에 base64(JSON)로 왕복 — 클라 계약 무변경.","hangul_chars":56,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"엔진 표준 응답 envelope.","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"2-way 세션 핸들 — jti에 base64(JSON)로 인코딩해 1차↔2차 왕복.","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":39,"line_end":41,"block_type":"line","text":"* ALB sticky 라우팅용 쿠키(`AWSALB`/`AWSALBCORS`). certify가 만든 박스로 treat을 보내려고\n*   certify 응답의 Set-Cookie를 여기에 담아 jti로 왕복시킨다. 없으면(단일박스/스티키 미사용) 생략.\n*   세션(jti)마다 고유하게 보관 → 전역 jar 없이 동시 사용자 격리. 라우팅용이라 PII 아님(로그 금지).","hangul_chars":80,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":58,"line_end":64,"block_type":"jsdoc","text":"응답 Set-Cookie 헤더(axios: string[] | string)에서 ALB sticky 쿠키만 골라\n  treat 요청 Cookie 헤더로 그대로 보낼 `name=value` 문자열로 합친다.\n  - `AWSALB`/`AWSALBCORS` 두 쿠키만 대상(다른 쿠키/세션 토큰은 무시 → 불필요 누출 방지).\n  - 하나도 없으면 undefined(하위호환: 단일박스/스티키 미사용 시 평소대로 동작).\n  - 쿠키 값은 라우팅용이라 민감도 낮지만 호출부에서 로깅하지 않는다.","hangul_chars":107,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* Set-Cookie 한 줄: \"AWSALB=xxx; Path=/; ...\" → 맨 앞 name=value 만 취한다.","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":81,"line_end":81,"block_type":"jsdoc","text":"엔진 성공 코드(result-codes.ts). 1차=추가인증필요, 2차=수집완료.","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":85,"line_end":88,"block_type":"jsdoc","text":"이 분류는 인프라/용량/기관 측 문제 → 어댑터가 throw하여 디스패처가 **다른 공급자로 폴백**하게 한다(블렌드).\n(유저 입력/인증 오류는 폴백해도 동일 실패 → 그대로 사용자에게 반환.)","hangul_chars":67,"class":"2_rationale","tags":["2_rationale"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/inhouse/src/inhouse.types.ts","lang":"js","line_start":96,"line_end":96,"block_type":"jsdoc","text":"inquiryType('0'건강 '1'자동차 '2'약) → 엔진 service / 결과 data 키.","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":1,"line_end":1,"block_type":"line","text":"* 메일 첨부파일 (nodemailer attachments 로 전달)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":3,"line_end":3,"block_type":"jsdoc","text":"첨부 파일명","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":6,"line_end":6,"block_type":"jsdoc","text":"파일 내용","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":14,"line_end":14,"block_type":"jsdoc","text":"발송 기업 ID (통계 메일 등 발신 주체 식별용 — 미사용 발송은 생략 가능)","hangul_chars":26,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":17,"line_end":17,"block_type":"jsdoc","text":"수신인 메일주소 (콤마구분 다중 수신 가능)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"메일 제목","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/mailer/src/mailer.interface.ts","lang":"js","line_start":29,"line_end":29,"block_type":"jsdoc","text":"첨부파일","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.crypto.ts","lang":"js","line_start":3,"line_end":3,"block_type":"line","text":"* 옥토버 암호문 prefix (가이드: doznenc_ + base64)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.crypto.ts","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"* 옥토버 기본 공개키(PEM). 공개값 — env(OCTOVER_RSA_PUBLIC_KEY) 미설정 시 사용.","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.crypto.ts","lang":"js","line_start":17,"line_end":21,"block_type":"jsdoc","text":"옥토버 PII 암호화 — RSA-OAEP(SHA-256) + base64 + \"doznenc_\" prefix.\n출처: developer.octover.co.kr/common/encryption (실호출 검증된 레퍼런스 기준).\n⚠️ CODEF/쿠콘과 패딩이 다름(쿠콘 AES, CODEF RSA-PKCS1). 옥토버는 OAEP 고정.","hangul_chars":36,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":9,"line_end":15,"block_type":"jsdoc","text":"옥토버 AB001 응답(data) → 내부 Treatment 계약(CODEF/쿠콘과 동일 res* 필드).\n매핑 근거: 레퍼런스 octover-hira-mapping.md(실호출 검증).\n - basicArray → resBasicTreatList (discountCharge=공단부담, selfCharge=본인부담)\n - detailArray → resDetailTreatList (diagnosisData=진료내역, oneDoseCount=1회투여횟수)\n - pharmacyArray → resPrescribeDrugList (IngredientName=성분명)","hangul_chars":49,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":24,"line_end":24,"block_type":"line","text":"* '$'/'해당없음' → 빈값 정규화","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":61,"line_end":70,"block_type":"jsdoc","text":"옥토버 자동차보험 AB001 응답(insureType=1) → 내부 Treatment(자동차 전용 필드 포함).\ncreateCarTreat→자동차 분석은 진료일수/의료비를 **자동차 전용 필드**(resTreatDate/resMedicalFee)에서 읽는다.\n  - resTreatDate(진료일수)  ← visitDateCount(내원일수)\n  - resTotalAmount(청구진료비 총금액) ← totalCharge (건강 매퍼가 이미 채움)\n  - resMedicalFee(자동차보험 총진료비) ← discountCharge(혜택받은금액=보험부담분)\n⚠️ 옥토버 자동차 응답은 건강과 동일 basicArray 구조라 '자동차보험 총진료비' 전용 필드가 없다.\n   discountCharge(보험부담) 로 근사한다. 옥토버 자동차 실응답으로 의미 검증 후 보정 필요.\n   (자동차는 처방 없음 → resPrescribeDrugList 는 건강 매퍼 결과상 빈 배열)","hangul_chars":173,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":72,"line_end":72,"block_type":"line","text":"* 건강 공통 필드(상병/병원/총액/세부) 재사용","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":76,"line_end":76,"block_type":"line","text":"* 진료일수","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.mapper.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* 자동차보험 총진료비(근사: 보험부담) — 실응답 검증 필요","hangul_chars":22,"class":"4_todo","tags":["4_todo"],"classified_by":"keyword","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":4,"line_end":8,"block_type":"jsdoc","text":"octover 자동차보험 연동(별도 AB001 호출) 분기 검증.\n - 건강/자동차 모두 성공 / 자동차 자료없음 / 자동차 실패 시 건강 성공 유지 / 자동차 미요청 / 건강 실패.\nhttp.post 를 목으로 옥토버 응답을 시뮬레이션한다(실호출 X).","hangul_chars":73,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":42,"line_end":42,"block_type":"line","text":"* 옥토버 응답 봉투: 로그인결과(성공) + AB001(코드/데이터)","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 자동차는 처방 없음","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":77,"line_end":77,"block_type":"line","text":"* createCarTreat→분석이 읽는 자동차 전용 필드","hangul_chars":12,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":78,"line_end":78,"block_type":"line","text":"* visitDateCount → 진료일수","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"* discountCharge → 자동차보험 총진료비(근사)","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":80,"line_end":81,"block_type":"line","text":"* totalCharge → 청구진료비 총금액\n* 건강 index 0 은 자동차 전용필드 미설정(건강 매퍼)","hangul_chars":25,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":126,"line_end":126,"block_type":"line","text":"* ── 부분성공 코드(정상등급) ──","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":141,"line_end":141,"block_type":"line","text":"* ── 자동차 실패는 건강 성공 보존 ──","hangul_chars":12,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":169,"line_end":169,"block_type":"line","text":"* ── 입력 방어 ──","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":182,"line_end":182,"block_type":"line","text":"* ── 응답 구조 변형: 자동차 basic만 있고 detail 없음(TreatService 부분허용이 흡수) ──","hangul_chars":21,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.spec.ts","lang":"js","line_start":192,"line_end":192,"block_type":"line","text":"* ── mobile(SMS) 인증 경로 ──","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":32,"line_end":43,"block_type":"jsdoc","text":"옥토버(Dozn Octover) 진료내역 공급자 — CODEF/쿠콘과 동일 TreatScraper 구현.\nTreatService가 provider 무관하게 호출(treatProvider='octover').\n\n인증 2종 (base.loginType):\n - '2' 휴대폰(문자): phoneVerify(1차) → phoneVerifyResult(SMS코드)+AB001(체인)\n - 그 외 간편: simpleAuthLogin(1차) → simpleAuthLoginResult+AB001(체인)\n\n⚠️ 로그인결과와 AB001 은 한 요청 methods 에 체인해야 함(분리 시 1000101). 레퍼런스 실호출 검증.\n2-way 세션(encInput)은 CODEF jti 자리에 base64 인코딩하여 클라 계약 무변경 왕복.\n범위: 건강보험 진료내역(보험종별 0)만. PII 는 RSA-OAEP 암호화.","hangul_chars":111,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"1차: 옥토버 본인인증 요청 → CODEF CertifyResponseDto(CF-03002) 정규화","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":124,"line_end":129,"block_type":"jsdoc","text":"2차: (로그인결과 + AB001) 체인 호출 → TreatmentMultipleResponseDto(data=[건강, 자동차]).\n - 건강(insureType=0)은 필수. 실패 시 전체 실패.\n - 건강 호출에서 connReq로 세션을 유지하고, 응답 header로 자동차 AB001을 이어서 호출한다.\n - 자동차 실패는 건강 성공을 뒤집지 않는 best-effort 정책이다.","hangul_chars":75,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":154,"line_end":154,"block_type":"line","text":"* 건강보험(insureType=0) — 필수. 자동차가 뒤따를 때만 연결 세션을 요청한다.","hangul_chars":24,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 자동차보험(insureType=1) — 건강 응답의 연결 header로 AB001만 이어서 호출.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":210,"line_end":213,"block_type":"jsdoc","text":"로그인결과 + AB001(insureType) 한 요청 체인 호출 → 매핑된 Treatment 반환.\n건강(insureType='0')/자동차('1') 공통. 실패 시 ok=false + failResult.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":226,"line_end":226,"block_type":"line","text":"* AB001 요청 파라미터(건강/자동차 공통).","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":228,"line_end":228,"block_type":"line","text":"* '0' 건강보험 / '1' 자동차보험(기본·세부진료만, 처방 없음)","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":229,"line_end":229,"block_type":"line","text":"* 주상병코드 포함","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":244,"line_end":244,"block_type":"line","text":"* 첫 거래만 로그인 결과를 검증한다. 자동차는 connHeader 세션으로 AB001만 호출한다.","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":254,"line_end":257,"block_type":"line","text":"* AB001(수집)은 OCTOVER_OK(1000200) 외에 시트 '정상등급' 코드도 성공으로 인정한다.\n*   1000204 내용없음(자료없음)/1000206 부분성공/1000210 마지막거래. node()는 본인인증 등과\n*   공용이라 엄격 OCTOVER_OK 유지하고, 수집 노드만 OCTOVER_COLLECT_OK 로 별도 판정.\n*   자료없음이면 data 가 비어도 매퍼가 빈 Treatment 를 반환 → 빈 분석 성공(환불 X).","hangul_chars":90,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":273,"line_end":273,"block_type":"line","text":"* 자동차(CAR)는 진료일수/자동차보험총진료비를 자동차 전용 필드로 채우는 매퍼 사용","hangul_chars":33,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.service.ts","lang":"js","line_start":329,"line_end":329,"block_type":"line","text":"* 메서드 노드 추출 + 성공코드 검증. 실패면 null.","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":1,"line_end":2,"block_type":"line","text":"* 옥토버(Dozn Octover) 심평원(HR1000N) 요청/응답 타입 + 봉투 헬퍼.\n* 실호출 검증된 레퍼런스(2026-06-04) 기준.","hangul_chars":28,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":5,"line_end":10,"block_type":"line","text":"* 메서드 노드 성공코드\n* 수집(AB001)에서 성공으로 인정할 코드 집합 — 옥토버 오류코드 시트 '정상등급(1)' 기준.\n*   1000204 자동연동 성공(내용 없음)=자료없음, 1000206 부분 성공, 1000210 마지막 거래 성공.\n*   자료없음은 빈 자료로 정상 처리(매퍼가 빈 Treatment 반환). 쿠콘 42110000과 동일 정책.\n*   ※ node()는 본인인증 등과 공용이라 OCTOVER_OK 엄격 유지하고, 수집 노드만 이 집합으로 판정.\n*   1000300('결괏값이 많아 조회불가')은 자료없음과 의미가 달라(데이터 자체를 못 받음) 제외.","hangul_chars":151,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":35,"line_end":38,"block_type":"jsdoc","text":"봉투 빌더. ⚠️ 로그인(결과)과 AB001 은 한 요청의 methods 배열에 함께 체인해야\n로그인이 본거래에 적용된다(분리 시 1000101 \"로그인 이후 이용 가능\"). 실호출 검증됨.","hangul_chars":54,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":55,"line_end":55,"block_type":"jsdoc","text":"단일 메서드 봉투 (1차 인증요청 등)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":79,"line_end":79,"block_type":"line","text":"── 입력 페이로드 ──","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":97,"line_end":97,"block_type":"line","text":"* '1' 주상병코드 포함","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":98,"line_end":98,"block_type":"line","text":"* '1' 민감상병 포함","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":110,"line_end":110,"block_type":"line","text":"* 없으면 '해당없음'","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":113,"line_end":113,"block_type":"line","text":"* 혜택받은금액 = 공단부담","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":114,"line_end":114,"block_type":"line","text":"* 내가낸의료비 = 본인부담","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":120,"line_end":120,"block_type":"line","text":"* 진료내역","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 처방/조제","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":149,"line_end":149,"block_type":"line","text":"── 우리 세션 핸들 (CODEF jti 자리에 base64 인코딩하여 왕복) ──","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":167,"line_end":167,"block_type":"line","text":"* 우리 loginTypeLevel(간편 상세: 1카카오/2페이코/3삼성/4KB/5PASS/6네이버/7신한/8토스) → 옥토버 loginType","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/octover/src/octover.types.ts","lang":"js","line_start":170,"line_end":170,"block_type":"line","text":"* 삼성패스","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":3,"line_end":3,"block_type":"line","text":"^----------------------------- 일반결제 (General Payment) -----------------------------^//","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":5,"line_end":5,"block_type":"jsdoc","text":"일반결제 승인 응답","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":7,"line_end":7,"block_type":"jsdoc","text":"성공 여부","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":15,"line_end":15,"block_type":"jsdoc","text":"결과코드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":19,"line_end":19,"block_type":"jsdoc","text":"결과메시지","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":24,"line_end":24,"block_type":"jsdoc","text":"결제금액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":29,"line_end":29,"block_type":"jsdoc","text":"주문번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":34,"line_end":34,"block_type":"jsdoc","text":"카드번호 (마스킹)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"카드사명","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":44,"line_end":44,"block_type":"jsdoc","text":"카드종류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":50,"line_end":50,"block_type":"jsdoc","text":"일반결제 취소 응답","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":52,"line_end":52,"block_type":"jsdoc","text":"성공 여부","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":60,"line_end":60,"block_type":"jsdoc","text":"취소일자","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":65,"line_end":65,"block_type":"jsdoc","text":"취소시간","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":70,"line_end":70,"block_type":"jsdoc","text":"취소금액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":75,"line_end":75,"block_type":"jsdoc","text":"결과코드","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.dto.ts","lang":"js","line_start":79,"line_end":79,"block_type":"jsdoc","text":"결과메시지","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":1,"line_end":1,"block_type":"line","text":"^----------------------------- 일반결제 (General Payment) -----------------------------^//","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":3,"line_end":3,"block_type":"jsdoc","text":"일반결제 요청 데이터 (프론트엔드 SDK용)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":7,"line_end":7,"block_type":"jsdoc","text":"전문일시 (yyyyMMddHHmmss)","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"암호화 데이터","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":11,"line_end":11,"block_type":"jsdoc","text":"주문번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":13,"line_end":13,"block_type":"jsdoc","text":"결제금액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":15,"line_end":15,"block_type":"jsdoc","text":"과세금액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":23,"line_end":23,"block_type":"jsdoc","text":"구매자명","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":25,"line_end":25,"block_type":"jsdoc","text":"구매자 연락처","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":27,"line_end":27,"block_type":"jsdoc","text":"구매자 이메일","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":31,"line_end":31,"block_type":"jsdoc","text":"일반결제 승인 요청","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"일반결제 취소 요청","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":43,"line_end":43,"block_type":"jsdoc","text":"취소 사유","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":45,"line_end":45,"block_type":"jsdoc","text":"취소할 금액","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.interface.ts","lang":"js","line_start":47,"line_end":47,"block_type":"jsdoc","text":"부분취소 여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":38,"line_end":38,"block_type":"line","text":"^----------------------------- 암호화 유틸리티 -----------------------------^//","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":40,"line_end":40,"block_type":"jsdoc","text":"SHA256 해시 후 Base64 인코딩","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":56,"line_end":56,"block_type":"jsdoc","text":"전문일시 생성 (yyyyMMddHHmmss)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":62,"line_end":62,"block_type":"line","text":"^----------------------------- 일반결제 (General Payment) -----------------------------^//","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":64,"line_end":64,"block_type":"jsdoc","text":"일반결제 상점ID 조회","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":69,"line_end":69,"block_type":"jsdoc","text":"일반결제 상점키 앞 32자리 조회 (AES256 암호화용)","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":74,"line_end":77,"block_type":"jsdoc","text":"일반결제 요청 데이터 생성 (프론트엔드 SDK용)\n@param params 결제 파라미터","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":96,"line_end":96,"block_type":"line","text":"* 부가세 계산 (총금액 = 과세금액 + 부가세)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":118,"line_end":118,"block_type":"jsdoc","text":"일반결제 승인 요청","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"* 결제 승인 실패 시 실패 결과 반환 (throw 하지 않음)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":138,"line_end":138,"block_type":"line","text":"* 결과 코드 확인 (0000: 성공, 3001: 카드결제 성공)","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"jsdoc","text":"일반결제 취소 요청","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/smartro/smartro.service.ts","lang":"js","line_start":170,"line_end":173,"block_type":"line","text":"* 부분취소 시 부가세 계산\nlet CancelTaxAmt = '';\nlet CancelVatAmt = '';\nlet CancelTaxFreeAmt = '';","hangul_chars":10,"class":"5_dead","tags":["5_dead"],"classified_by":"code","commented_out":true,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":12,"line_end":12,"block_type":"jsdoc","text":"카드발급사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":16,"line_end":16,"block_type":"jsdoc","text":"카드매입사","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"카드번호 (일부 마스킹: 11112222****333*)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":24,"line_end":24,"block_type":"jsdoc","text":"카드 종류","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":28,"line_end":28,"block_type":"jsdoc","text":"카드 소유자","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"결제 카드정보","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"할부개월수","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":39,"line_end":39,"block_type":"jsdoc","text":"무이자 할부의 적용 여부","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":42,"line_end":42,"block_type":"jsdoc","text":"할부가 적용된 결제에서 할부 수수료를 부담하는 주체","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":46,"line_end":46,"block_type":"jsdoc","text":"카드사 승인 번호","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":50,"line_end":50,"block_type":"jsdoc","text":"카드사 포인트 사용 여부","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":54,"line_end":60,"block_type":"jsdoc","text":"카드 결제의 매입 상태\n- READY: 아직 매입 요청이 안 된 상태입니다.\n- REQUESTED: 매입이 요청된 상태입니다.\n- COMPLETED: 요청된 매입이 완료된 상태입니다.\n- CANCEL_REQUESTED: 매입 취소가 요청된 상태입니다.\n- CANCELED: 요청된 매입 취소가 완료된 상태입니다.","hangul_chars":77,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":69,"line_end":69,"block_type":"jsdoc","text":"카드사에 결제 요청한 금액","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":74,"line_end":74,"block_type":"jsdoc","text":"결제 영수증 정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":80,"line_end":80,"block_type":"jsdoc","text":"결제 결제창 정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":86,"line_end":86,"block_type":"jsdoc","text":"결제취소 취소 정보","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"^----------------------------- 빌링키 생성  -----------------------------^//","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":131,"line_end":131,"block_type":"jsdoc","text":"빌링키 생성 응답정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":133,"line_end":133,"block_type":"jsdoc","text":"상점ID (최대 14자리)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":138,"line_end":138,"block_type":"jsdoc","text":"구매자ID(=구독자코드)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":141,"line_end":144,"block_type":"jsdoc","text":"인증시간 (yyyy-MM-dd'T'HH:mm:ss±mm)\n- ex) 2021-01-01T10:00:00+09:00","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":148,"line_end":148,"block_type":"jsdoc","text":"결제수단 (자동결제는 카드 고정)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":156,"line_end":156,"block_type":"jsdoc","text":"카드회사","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":160,"line_end":160,"block_type":"jsdoc","text":"카드번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":164,"line_end":164,"block_type":"jsdoc","text":"등록된 카드정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":170,"line_end":170,"block_type":"jsdoc","text":"빌링키 카드정보","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":172,"line_end":172,"block_type":"jsdoc","text":"카드 매입사/발급사","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":201,"line_end":202,"block_type":"line","text":"^----------------------------- 빌링키 결제 / 취소 -----------------------------^//\n* 결제요청과 결제취소요청의 응답값이 동일하나 Cancels값이 취소엔 필수값으로 들어감","hangul_chars":40,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":204,"line_end":204,"block_type":"jsdoc","text":"결제실패시 실패에러","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":209,"line_end":209,"block_type":"jsdoc","text":"상점ID (최대 14자리)","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":213,"line_end":213,"block_type":"jsdoc","text":"마지막 거래의 키 값","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":222,"line_end":222,"block_type":"jsdoc","text":"주문번호","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":232,"line_end":241,"block_type":"jsdoc","text":"- READY: 결제를 생성하면 가지게 되는 초기 상태, 인증 전까지는 READY 상태를 유지.\n- IN_PROGRESS: 결제수단 정보와 해당 결제수단의 소유자가 맞는지 인증을 마친 상태. 결제 승인 API를 호출하면 결제가 완료.\n- WAITING_FOR_DEPOSIT: 가상계좌 결제 흐름에만 있는 상태. 발급된 가상계좌에 구매자가 아직 입금하지 않은 상태.\n- DONE: 인증된 결제수단으로 요청한 결제가 승인된 상태.\n- CANCELED: 승인된 결제가 취소된 상태.\n- PARTIAL_CANCELED: 승인된 결제가 부분 취소된 상태.\n- ABORTED: 결제 승인이 실패한 상태.\n- EXPIRED: 결제 유효 시간 30분이 지나 거래가 취소된 상태. IN_PROGRESS 상태에서 결제 승인 API를 호출하지 않으면 EXPIRED가 됨.","hangul_chars":195,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":253,"line_end":253,"block_type":"jsdoc","text":"결제가 일어난 날짜와 시간 정보 (ex: yyyy-MM-dd'T'HH:mm:ss±hh:mm ISO 8601 형식)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":257,"line_end":257,"block_type":"jsdoc","text":"결제 승인이 일어난 날짜와 시간 정보 (ex: yyyy-MM-dd'T'HH:mm:ss±hh:mm ISO 8601 형식)","hangul_chars":17,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":262,"line_end":262,"block_type":"jsdoc","text":"에스크로 사용 여부","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":266,"line_end":266,"block_type":"jsdoc","text":"문화비(도서, 공연 티켓, 박물관·미술관 입장권 등) 지출 여부입니다. 계좌이체, 가상계좌 결제에만 적용","hangul_chars":40,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":274,"line_end":274,"block_type":"jsdoc","text":"웹훅을 검증하는 최대 50자 값","hangul_chars":11,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":279,"line_end":279,"block_type":"jsdoc","text":"결제 타입 정보 NORMAL(일반결제), BILLING(자동결제), BRANDPAY(브랜드페이)중 하나","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":292,"line_end":292,"block_type":"jsdoc","text":"부분 취소 가능 여부입니다. 이 값이 false이면 전액 취소만 가능","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":296,"line_end":296,"block_type":"jsdoc","text":"발행된 영수증 정보 (객체)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":302,"line_end":302,"block_type":"jsdoc","text":"결제창 정보 (객체)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":316,"line_end":316,"block_type":"jsdoc","text":"결제시 사용한 통화","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":320,"line_end":320,"block_type":"jsdoc","text":"총결제금액(결제가 취소되는 등 결제 상태가 변해도 최초에 결제된 결제 금액으로 유지)","hangul_chars":35,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":324,"line_end":324,"block_type":"jsdoc","text":"취소할 수 있는 금액(잔고)","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":328,"line_end":328,"block_type":"jsdoc","text":"공급가액","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":336,"line_end":336,"block_type":"jsdoc","text":"결제 금액 중 면세 금액","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":340,"line_end":340,"block_type":"jsdoc","text":"결제수단 (자동결제는 카드 고정)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":344,"line_end":344,"block_type":"jsdoc","text":"Payment 객체의 응답 버전","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":348,"line_end":348,"block_type":"jsdoc","text":"가상계좌로 결제하면 제공되는 가상계좌 관련 정보 (객체)","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":350,"line_end":350,"block_type":"jsdoc","text":"계좌이체로 결제했을 때 이체 정보가 담기는 객체","hangul_chars":20,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":353,"line_end":353,"block_type":"jsdoc","text":"휴대폰으로 결제하면 제공되는 휴대폰 결제 관련 정보 (객체)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":356,"line_end":356,"block_type":"jsdoc","text":"상품권으로 결제하면 제공되는 상품권 결제 관련 정보(객체)","hangul_chars":24,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":359,"line_end":359,"block_type":"jsdoc","text":"현금영수증 정보 (객체)","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":362,"line_end":362,"block_type":"jsdoc","text":"결제 요청 시 직접 추가할 수 있는 결제 관련 정보(객체)","hangul_chars":21,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":365,"line_end":365,"block_type":"jsdoc","text":"현금영수증 발행 및 취소 이력이 담기는 배열","hangul_chars":18,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":368,"line_end":368,"block_type":"jsdoc","text":"카드사 및 퀵계좌이체의 즉시 할인 프로모션 정보(객체). 즉시 할인 프로모션이 적용됐을 때만 생성","hangul_chars":39,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":371,"line_end":371,"block_type":"jsdoc","text":"간편결제 정보(객체)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.dto.ts","lang":"js","line_start":374,"line_end":374,"block_type":"jsdoc","text":"결제 실패 정보 (객체)","hangul_chars":8,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.interface.ts","lang":"js","line_start":1,"line_end":1,"block_type":"jsdoc","text":"빌링키 생성 요청정보","hangul_chars":9,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.interface.ts","lang":"js","line_start":7,"line_end":7,"block_type":"jsdoc","text":"빌링키 결제요청","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.interface.ts","lang":"js","line_start":16,"line_end":16,"block_type":"jsdoc","text":"결제취소","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.interface.ts","lang":"js","line_start":18,"line_end":18,"block_type":"jsdoc","text":"취소 사유","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.interface.ts","lang":"js","line_start":20,"line_end":20,"block_type":"jsdoc","text":"취소할 금액(없을 경우 전액취소)","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"jsdoc","text":"빌링키 발급","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.service.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"빌링키 결제요청","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.service.ts","lang":"js","line_start":67,"line_end":67,"block_type":"line","text":"* 결제실패사유 저장을 위한 반환","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.service.ts","lang":"js","line_start":84,"line_end":84,"block_type":"jsdoc","text":"결제취소","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/pg/src/toss/toss.service.ts","lang":"js","line_start":99,"line_end":99,"block_type":"line","text":"* 결제취소 실패사유 저장필요없음 throw 처리","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.constant.ts","lang":"js","line_start":1,"line_end":6,"block_type":"jsdoc","text":"result 코드 → 한글 사유 매핑\n\nFAX_RESULT (알파벳): 팩스 송수신 결과 (HTTP 200)\nERR_* (숫자): API/시스템 오류 (HTTP 에러)","hangul_chars":27,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.constant.ts","lang":"js","line_start":8,"line_end":8,"block_type":"line","text":"FAX_RESULT - 팩스 송수신 결과","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.constant.ts","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"ERR_* - API/시스템 오류","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.constant.ts","lang":"js","line_start":44,"line_end":44,"block_type":"jsdoc","text":"sendStatus → 한글 상태명","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.constant.ts","lang":"js","line_start":54,"line_end":54,"block_type":"jsdoc","text":"result 코드로 사유 텍스트 반환","hangul_chars":10,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":3,"line_end":3,"block_type":"jsdoc","text":"발송 성공 여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":7,"line_end":7,"block_type":"jsdoc","text":"페이지 수 (성공 시)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":9,"line_end":9,"block_type":"jsdoc","text":"실패 사유 (실패 시)","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":21,"line_end":21,"block_type":"jsdoc","text":"실패 사유 (FAILED 시)","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":23,"line_end":23,"block_type":"jsdoc","text":"원본 응답","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":29,"line_end":29,"block_type":"jsdoc","text":"취소 성공 여부","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":31,"line_end":31,"block_type":"jsdoc","text":"이미 발송된 건이라서 취소 실패한 경우","hangul_chars":16,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.dto.ts","lang":"js","line_start":33,"line_end":33,"block_type":"jsdoc","text":"실패 사유","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":31,"line_end":31,"block_type":"jsdoc","text":"팩스 발송 (soft failure - 실패사유를 호출측에서 히스토리에 기록해야 하므로 throw 하지 않음)","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":98,"line_end":98,"block_type":"jsdoc","text":"발송 상태 조회 (soft failure - HTTP 에러 시에도 결과 반환)","hangul_chars":15,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":115,"line_end":115,"block_type":"line","text":"HTTP 에러인 경우","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":127,"line_end":127,"block_type":"line","text":"sendStatus 기반 분기","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":129,"line_end":129,"block_type":"line","text":"예약취소","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":134,"line_end":134,"block_type":"line","text":"아직 발송 중","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":139,"line_end":139,"block_type":"line","text":"결과 수신 완료","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":152,"line_end":152,"block_type":"line","text":"알 수 없는 sendStatus","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":161,"line_end":161,"block_type":"jsdoc","text":"발송 취소","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/vfax/src/vfax.service.ts","lang":"js","line_start":178,"line_end":178,"block_type":"line","text":"이미 발송된 건","hangul_chars":6,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":18,"line_end":19,"block_type":"line","text":"* 응답 본문 + 헤더를 함께 돌려주는 래퍼. 기본 post/get은 본문만(response.data) 반환하므로\n*   Set-Cookie 같은 응답 헤더가 필요한 호출(예: inhouse ALB sticky)은 이걸 쓴다.","hangul_chars":44,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":34,"line_end":34,"block_type":"line","text":"* 본문과 응답 헤더를 함께 반환(Set-Cookie 등). 헤더가 필요 없으면 post/get을 그대로 쓰면 된다.","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":45,"line_end":46,"block_type":"line","text":"* 본문만 반환하는 기본 client와 달리, 응답 헤더가 필요한 호출용(Set-Cookie 등).\n*   response 인터셉터가 response.data로 줄여버리지 않게 별도 인스턴스를 둔다.","hangul_chars":46,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":50,"line_end":52,"block_type":"line","text":"* 로그 마스킹(보안감사 C5): 민감 헤더(x-api-key/authorization/cookie)·PII 필드(이름/주민/폰/생년/\n*   통신사/이메일/주소)를 로그에 평문으로 남기지 않는다. certify 바디·엔진 api-key·진료응답이 평문으로\n*   찍히던 걸 차단. (디버그 가치는 유지 — 비민감 필드는 그대로, 민감 키만 ***)","hangul_chars":84,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":88,"line_end":88,"block_type":"line","text":"* 요청 로깅 인터셉터(두 인스턴스 공용). 헤더·바디의 민감정보는 위 redact로 마스킹.","hangul_chars":30,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/webclient/src/webclient.service.ts","lang":"js","line_start":138,"line_end":139,"block_type":"line","text":"* rawClient: 본문+헤더 전체를 그대로 돌려준다(response.data로 축약 X).\n*   에러 로깅만 붙이고, Set-Cookie가 헤더에 실릴 수 있어 성공 응답 본문/헤더는 로깅하지 않는다.","hangul_chars":50,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/youtube/src/youtube.service.ts","lang":"js","line_start":27,"line_end":27,"block_type":"line","text":"영상 길이는 contentDetails 필드에 포함됩니다.","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/youtube/src/youtube.service.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"PT1H2M3S와 같은 ISO 8601 형식","hangul_chars":5,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"libs/youtube/src/youtube.service.ts","lang":"js","line_start":37,"line_end":37,"block_type":"line","text":"ISO 8601 duration을 초 단위로 변환하는 함수 호출","hangul_chars":13,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/download-all-invoice.js","lang":"js","line_start":4,"line_end":6,"block_type":"jsdoc","text":"모든 보험사에 관한 청구서를 다운로드합니다.","hangul_chars":19,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/download-all-invoice.js","lang":"js","line_start":94,"line_end":94,"block_type":"line","text":"바이너리 데이터를 arraybuffer로 받도록 설정","hangul_chars":14,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/download-all-invoice.js","lang":"js","line_start":100,"line_end":100,"block_type":"line","text":"binary 옵션 추가","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/run-task688-migration.ts","lang":"js","line_start":9,"line_end":24,"block_type":"jsdoc","text":"task-688 — 기업↔기업상품 1:N 전환을 위한 백필 마이그레이션 실행 진입점.\n\n실행:\n  - ts-node 사용 시: `ts-node -r tsconfig-paths/register scripts/run-task688-migration.ts`\n  - 빌드 후 실행 시: nest build 산출물 경로에 맞춰 require 경로 조정 후 node 실행.\n\n동작:\n 1) NestJS 표준 부트스트랩으로 AppModule 컨텍스트 생성(HTTP 미바인딩).\n 2) DrizzleService 인스턴스 획득 후 runDefaultOrganizationMigration 1회 호출.\n 3) 결과 통계 출력 후 컨텍스트 종료.\n\n멱등성:\n - 이미 매핑된 행은 다시 건드리지 않으므로 안전하게 재실행 가능.\n - NOT NULL ALTER DDL 은 본 스크립트 완료 후 별도 단계에서 수행 권장.","hangul_chars":142,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/run-task688-migration.ts","lang":"js","line_start":33,"line_end":33,"block_type":"line","text":"* 운영 1회 실행을 가정한 결과 보고 — 콘솔 출력만으로 충분.","hangul_chars":22,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/schemaPrimaryKeyUpdater.mjs","lang":"js","line_start":6,"line_end":6,"block_type":"line","text":"파일 읽기","hangul_chars":4,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/schemaPrimaryKeyUpdater.mjs","lang":"js","line_start":20,"line_end":20,"block_type":"line","text":"변경된 내용 저장","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/treat-daily-verify.ts","lang":"js","line_start":1,"line_end":15,"block_type":"jsdoc","text":"일별 총합계 검증 — TreatMonitorService.dailySummary 와 '완전히 동일한' 로직을 prod DB에 직접 돌려\n 엑셀(삼성화재_진료모니터링_일별총합계_*.xlsx / 벤더 통합)과 숫자를 대조한다.\n - 분류(진짜이탈/유저실패/시스템실패)는 실서비스 VENDOR_MAP·USER_FAIL_CATS 를 그대로 import → 정의 100% 일치.\n - prod 읽기전용 집계 전용. 비번은 MYSQL_PWD env 로만(명령줄 노출 금지). ltr_created_at 은 KST 저장 → CONVERT_TZ 금지.\n\n사용:\n  cd ~/projects/work/insuniverse/server\n  MYSQL_PWD='운영DB비번' TS_NODE_TRANSPILE_ONLY=1 TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' \\\n    TDB_PORT=13307 TDB_USER=admin FROM=2026-07-06 TO=2026-07-20 \\\n    npx ts-node scripts/treat-daily-verify.ts\n\n ※ 엑셀 '일별 총합계'는 대상=삼성화재 계정이지만, 본 스크립트는 전체 통합(dailySummary와 동일 범위)이라\n   삼성화재가 전체와 다르면 숫자가 다를 수 있음. 코호트 로직/일자 정합 검증이 1차 목적.","hangul_chars":180,"class":"1_policy","tags":["1_policy"],"classified_by":"keyword","commented_out":false,"policy_candidate":true,"legal_boilerplate":false}
{"file":"scripts/treat-daily-verify.ts","lang":"js","line_start":32,"line_end":32,"block_type":"line","text":"* 기업상품(PRD003) 코드 다중필터 — PRODUCTS='코드1,코드2'. 미지정이면 전체 통합.","hangul_chars":23,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/treat-daily-verify.ts","lang":"js","line_start":35,"line_end":35,"block_type":"line","text":"* 실서비스 USER_FAIL_CATS 와 동일","hangul_chars":7,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"scripts/treat-daily-verify.ts","lang":"js","line_start":64,"line_end":64,"block_type":"line","text":"* 발견 모드 — 기업상품(PRD003) 코드/명 목록만 찍고 종료. 삼성화재 상품코드 찾을 때: LIST_PRODUCTS=1","hangul_chars":29,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
{"file":"test/jest-drizzle-stub.js","lang":"js","line_start":1,"line_end":2,"block_type":"line","text":"drizzle/schema 등 스키마 모듈 스텁 — 어떤 named import든 빈 객체 반환.\ndispatcher 통합 테스트는 repository 쿼리를 호출하지 않으므로 스키마 실체 불필요.","hangul_chars":41,"class":"3_impl","tags":[],"classified_by":"fallback","commented_out":false,"policy_candidate":false,"legal_boilerplate":false}
