[{"data":1,"prerenderedAt":747},["ShallowReactive",2],{"doc:\u002Fhistory\u002Fhistory.20260608":3},{"id":4,"title":5,"body":6,"description":715,"extension":740,"meta":741,"navigation":742,"path":743,"seo":744,"stem":745,"__hash__":746},"docs\u002Fhistory\u002Fhistory.20260608.md","작업 이력 — 2026-06-08",{"type":7,"value":8,"toc":714},"minimark",[9,13,17,31,36,44,133,137,143,232,239,243,246,337,346,350,368,488,491,495,516,519,538,542,602,605,608,615,648,656,666,672,682,688,698,704],[10,11,5],"h1",{"id":12},"작업-이력-2026-06-08",[14,15,16],"h2",{"id":16},"종합",[18,19,20,21,30],"p",{},"오늘 4개 흐름 — ",[22,23,24,25,29],"strong",{},"관리자단(",[26,27,28],"code",{},"malgn-helper-admin",") 기획부터 실 운영 화면·인증까지 일괄 진입",".",[32,33,35],"h3",{"id":34},"_1-admin-plan-기획서-완성-6-라운드","1. ADMIN-PLAN 기획서 완성 (6 라운드)",[18,37,38,43],{},[39,40,42],"a",{"href":41},"..\u002FADMIN-PLAN","doc\u002FADMIN-PLAN.md"," 신설 + 5회 갱신:",[45,46,47,54,71,99,113,123],"ul",{},[48,49,50,53],"li",{},[22,51,52],{},"1차",": IA(12 섹션) + 화면 명세 12종 + Week 1~5 단계별 구현",[48,55,56,59,60,63,64,63,67,70],{},[22,57,58],{},"2차",": 3 역할 (",[26,61,62],{},"admin","\u002F",[26,65,66],{},"developer",[26,68,69],{},"agent",") 권한 매트릭스 + 동영상 URL 정책 (Whisper 수동 트리거) + 운영 기본값 5건 확정",[48,72,73,76,77,80,81,80,84,80,87,90,91,94,95,98],{},[22,74,75],{},"3차",": 표준답변 분류 체계 (",[26,78,79],{},"scope"," + ",[26,82,83],{},"topic",[26,85,86],{},"service_tag",[26,88,89],{},"tags",") + 이미지 자동 배치 3방식 + AI 초안 = ",[26,92,93],{},"POST \u002Fchat"," 재사용 + ",[26,96,97],{},"\u002Funcovered"," 전용 페이지",[48,100,101,104,105,108,109,112],{},[22,102,103],{},"4차",": ",[26,106,107],{},"lms-private"," → ",[26,110,111],{},"lms-security"," 라벨 변경 (민간보안 LMS 도메인 명시)",[48,114,115,118,119,122],{},[22,116,117],{},"5차",": 사이드바 메뉴 §3-2~3-5 정의 — ",[22,120,121],{},"5 그룹 × 17 메뉴",", 권한별 가시성, heroicons 아이콘",[48,124,125,128,129,132],{},[22,126,127],{},"6차",": '미커버 질문' 정의 명확화 — 답변 없는 PMS 게시물(",[26,130,131],{},"inquiry-only",")과 구분",[32,134,136],{"id":135},"_2-admin-골격-구현-handoff_noti-디자인-톤-차용","2. admin 골격 구현 (handoff_noti 디자인 톤 차용)",[18,138,139,140,30],{},"빈 보일러플레이트 → ",[22,141,142],{},"256px LNB + 64px TopBar + 17 페이지 stub",[144,145,146,159],"table",{},[147,148,149],"thead",{},[150,151,152,156],"tr",{},[153,154,155],"th",{},"영역",[153,157,158],{},"파일",[160,161,162,181,192,208,221],"tbody",{},[150,163,164,168],{},[165,166,167],"td",{},"의존성",[165,169,170,173,174,173,177,180],{},[26,171,172],{},"@nuxt\u002Fui@3.3.7"," · ",[26,175,176],{},"@tailwindcss\u002Fvite@4.3",[26,178,179],{},"lucide-vue-next"," · DM Sans + Pretendard",[150,182,183,186],{},[165,184,185],{},"메뉴 데이터",[165,187,188,191],{},[26,189,190],{},"composables\u002Fuse-admin-menu.ts"," — 5 그룹 × 17 메뉴 + 권한·배지 + 검색",[150,193,194,197],{},[165,195,196],{},"컴포넌트",[165,198,199,173,202,173,205],{},[26,200,201],{},"SidebarMenu.vue",[26,203,204],{},"TopBar.vue",[26,206,207],{},"PagePlaceholder.vue",[150,209,210,213],{},[165,211,212],{},"레이아웃",[165,214,215,173,218],{},[26,216,217],{},"layouts\u002Fdefault.vue",[26,219,220],{},"app.vue",[150,222,223,226],{},[165,224,225],{},"페이지",[165,227,228,231],{},[26,229,230],{},"pages\u002Findex.vue"," (홈 KPI mockup) + 16개 stub",[18,233,234,235,238],{},"초기 ",[26,236,237],{},"@nuxt\u002Fui"," v4 설치 후 Nuxt 3 호환 미충족 발견 → v3.3.7로 다운그레이드.",[32,240,242],{"id":241},"_3-1순위-4-화면-실데이터-구현","3. 1순위 4 화면 실데이터 구현",[18,244,245],{},"PMS의 기존 데이터·컴포넌트를 admin에서 즉시 활용 가능한 4 메뉴 구현:",[144,247,248,261],{},[147,249,250],{},[150,251,252,255,258],{},[153,253,254],{},"화면",[153,256,257],{},"데이터 소스",[153,259,260],{},"핵심",[160,262,263,282,298,320],{},[150,264,265,270,279],{},[165,266,267,269],{},[26,268,63],{}," 홈",[165,271,272,275,276],{},[22,273,274],{},"신규"," ",[26,277,278],{},"GET \u002Fadmin\u002Fkpi",[165,280,281],{},"실 KPI 4 카드 (표준답변·이미지·평가·이번 달 비용) + 최근 활동 10건",[150,283,284,289,295],{},[165,285,286],{},[26,287,288],{},"\u002Fcost",[165,290,291,292],{},"기존 ",[26,293,294],{},"GET \u002Fadmin\u002Fcost",[165,296,297],{},"7\u002F30\u002F90일 토글 + KPI 4 + 모델별 표 + 일별 추이 + 엔티티 분포 + 최근 호출 50건",[150,299,300,305,310],{},[165,301,302],{},[26,303,304],{},"\u002Fqa-evals",[165,306,291,307],{},[26,308,309],{},"GET \u002Fadmin\u002Fevals",[165,311,312,313],{},"정렬 4종(최신·점수↑·점수↓·지연) + 빈 결과 필터. 행 클릭 → ",[22,314,315,316,319],{},"PMS ",[26,317,318],{},"\u002Fposts\u002F:id\u002Feval"," iframe 모달",[150,321,322,327,334],{},[165,323,324],{},[26,325,326],{},"\u002Fimages",[165,328,329,275,331],{},[22,330,274],{},[26,332,333],{},"GET \u002Fimage-assets",[165,335,336],{},"디바운스 검색 + source 필터 + 4:3 그리드 + 상세 모달(원본 + 메타)",[18,338,339,340,342,343,30],{},"API 신규 2개 — ",[26,341,278],{},", ",[26,344,345],{},"GET \u002Fimage-assets(\u002F:id)",[32,347,349],{"id":348},"_4-tb_user-통합-로그인-외부-sso-결정-tb_user-변경","4. tb_user 통합 로그인 (외부 SSO 결정 → tb_user 변경)",[18,351,352,353,367],{},"처음 외부 SSO 패턴 고려했다가 ",[22,354,355,356,359,360,80,363,366],{},"PMS의 ",[26,357,358],{},"tb_user","(",[26,361,362],{},"login_id",[26,364,365],{},"passwd"," SHA-256)를 그대로 사용","하는 통합 인증으로 결정.",[144,369,370,379],{},[147,371,372],{},[150,373,374,376],{},[153,375,155],{},[153,377,378],{},"변경",[160,380,381,398,412,428,446,457,473],{},[150,382,383,388],{},[165,384,385],{},[26,386,387],{},"wrangler secret",[165,389,390,393,394,397],{},[26,391,392],{},"JWT_SECRET"," 등록 (",[26,395,396],{},"openssl rand -hex 32",")",[150,399,400,403],{},[165,401,402],{},"CORS",[165,404,405,80,408,411],{},[26,406,407],{},"credentials: true",[26,409,410],{},"Authorization"," 헤더 허용",[150,413,414,417],{},[165,415,416],{},"API 엔드포인트",[165,418,419,173,422,173,425],{},[26,420,421],{},"POST \u002Fauth\u002Flogin",[26,423,424],{},"POST \u002Fauth\u002Flogout",[26,426,427],{},"GET \u002Fauth\u002Fme",[150,429,430,433],{},[165,431,432],{},"검증 흐름",[165,434,435,438,439,442,443,397],{},[26,436,437],{},"tb_user.passwd === sha256(input)"," + 직원 룰(",[26,440,441],{},"@malgnsoft.com"," OR ",[26,444,445],{},"company='맑은소프트'",[150,447,448,451],{},[165,449,450],{},"세션",[165,452,453,454],{},"JWT 8h, ",[26,455,456],{},"Set-Cookie helper_session=...; HttpOnly; Secure; SameSite=None",[150,458,459,461],{},[165,460,62],{},[165,462,463,173,466,173,469,472],{},[26,464,465],{},"composables\u002Fuse-auth.ts",[26,467,468],{},"middleware\u002Fauth.global.ts",[26,470,471],{},"pages\u002Flogin.vue"," · 사이드바·TopBar 실 사용자·로그아웃",[150,474,475,478],{},[165,476,477],{},"역할 매핑",[165,479,480,483,484,487],{},[26,481,482],{},"level ≥ 9"," admin \u002F ",[26,485,486],{},"≥ 5"," developer \u002F 그 외 agent",[18,489,490],{},"PMS는 인증 강제 X (현 흐름 유지).",[32,492,494],{"id":493},"결정사건","결정\u002F사건",[45,496,497,504,510,513],{},[48,498,499,500,503],{},"외부 사이트 SSO 패턴 검토 후 ",[22,501,502],{},"tb_user 통합으로 전환"," — 인증 책임이 한 곳에 집중되어 일관성·관리성 ↑",[48,505,506,509],{},[22,507,508],{},"SHA-256 단독 hash 약점"," 인지 — 운영 강화 시 bcrypt\u002Fargon2 마이그레이션 (첫 로그인 시 재해시) 권장 (보안 메모)",[48,511,512],{},"handoff_noti_admin 디자인을 admin 톤의 베이스로 차용 — 컴포넌트 룩앤필만, 콘텐츠는 우리 메뉴",[48,514,515],{},"미커버 질문 = 챗봇 운영 후 자동 수집 (Phase 2). 답변 없는 PMS 게시물(inquiry-only)과 별개임을 명확히",[32,517,518],{"id":518},"검증",[45,520,521,530],{},[48,522,523,108,526,529],{},[26,524,525],{},"POST \u002Fauth\u002Flogin {\"loginId\":\"1\",\"password\":\"wrong\"}",[26,527,528],{},"{\"error\":\"invalid credentials\"}"," 401 ✅",[48,531,532,108,534,537],{},[26,533,278],{},[26,535,536],{},"{ standardAnswers: 3, images: 24, evals: 35, avgScore: 3.7, monthCalls: 112 }"," 실데이터 ✅",[32,539,541],{"id":540},"다음-작업-후보","다음 작업 후보",[45,543,544,568,586,596],{},[48,545,546,549,550,80,553,556,557,560,561,173,564,567],{},[22,547,548],{},"2순위 마이그레이션"," — ",[26,551,552],{},"hp_topic",[26,554,555],{},"hp_service"," 신설 + ",[26,558,559],{},"hp_standard_answer"," 컬럼 보강 → ",[26,562,563],{},"\u002Fcatalog",[26,565,566],{},"\u002Fstandard-answers"," 정식 활성",[48,569,570,578,579,173,582,585],{},[22,571,572,80,575],{},[26,573,574],{},"hp_account",[26,576,577],{},"hp_audit_log"," 신설 → admin ",[26,580,581],{},"\u002Faccounts",[26,583,584],{},"\u002Faudit-logs"," 동작",[48,587,588,595],{},[22,589,590,591,594],{},"API 라우트별 ",[26,592,593],{},"requireAuth\u002FrequireRole"," 미들웨어 적용"," — 현재 인증 검증은 admin 측만, API는 무인증 호출 가능",[48,597,598,601],{},[22,599,600],{},"SHA-256 → bcrypt 마이그레이션 계획"," (보안 강화)",[603,604],"hr",{},[14,606,607],{"id":607},"배포",[32,609,611,612,614],{"id":610},"_1617-malgn-helper-admin-cloudflare-pages","16:17 — ",[26,613,28],{}," → Cloudflare Pages",[45,616,617,624,627,630,633,636,639,642,645],{},[48,618,619,620,623],{},"커밋: ",[26,621,622],{},"b3cfcad"," (신규 커밋: yes)",[48,625,626],{},"메시지: feat(admin): 사이드바 메뉴 구조 + 레이아웃 + 17 페이지 stub (handoff_noti 디자인 톤 적용)",[48,628,629],{},"Nuxt UI v3 + Tailwind v4 + Lucide + DM Sans\u002FPretendard 도입",[48,631,632],{},"composables\u002Fuse-admin-menu.ts: 5 그룹 × 17 메뉴 + 권한·배지 정의",[48,634,635],{},"components\u002Fadmin\u002FSidebarMenu.vue: 256px LNB (브랜드·검색·그룹 접기·뱃지·사용자칩)",[48,637,638],{},"components\u002Fadmin\u002FTopBar.vue: 64px sticky (breadcrumb·검색·환경 토글·알림·로그아웃)",[48,640,641],{},"layouts\u002Fdefault.vue + app.vue 골격",[48,643,644],{},"pages\u002Findex.vue: 홈 KPI 4종 + 최근 활동 mockup",[48,646,647],{},"pages\u002F{16개} stub: AdminPagePlaceholder 컴포넌트로 통일",[32,649,651,652,655],{"id":650},"_1642-malgn-helper-api-cloudflare-workers","16:42 — ",[26,653,654],{},"malgn-helper-api"," → Cloudflare Workers",[45,657,658,663],{},[48,659,619,660,623],{},[26,661,662],{},"cc7fc47",[48,664,665],{},"메시지: feat(api): GET \u002Fimage-assets + GET \u002Fadmin\u002Fkpi — admin 1순위 화면 데이터 소스",[32,667,669,670,614],{"id":668},"_1650-malgn-helper-admin-cloudflare-pages","16:50 — ",[26,671,28],{},[45,673,674,679],{},[48,675,619,676,623],{},[26,677,678],{},"69db1e8",[48,680,681],{},"메시지: feat(admin 1순위): 홈 KPI 실데이터 + \u002Fcost + \u002Fqa-evals(iframe 모달) + \u002Fimages 그리드",[32,683,685,686,655],{"id":684},"_1737-malgn-helper-api-cloudflare-workers","17:37 — ",[26,687,654],{},[45,689,690,695],{},[48,691,619,692,623],{},[26,693,694],{},"cfe84a4",[48,696,697],{},"메시지: feat(auth): \u002Fauth\u002Flogin·logout·me + JWT(8h httpOnly cookie) — tb_user 통합 인증",[32,699,701,702,614],{"id":700},"_1740-malgn-helper-admin-cloudflare-pages","17:40 — ",[26,703,28],{},[45,705,706,711],{},[48,707,619,708,623],{},[26,709,710],{},"6f412e5",[48,712,713],{},"메시지: feat(auth): tb_user 통합 로그인 — \u002Flogin + auth.global 미들웨어 + JWT httpOnly cookie 세션 (8h)",{"title":715,"searchDepth":716,"depth":716,"links":717},"",3,[718,728],{"id":16,"depth":719,"text":16,"children":720},2,[721,722,723,724,725,726,727],{"id":34,"depth":716,"text":35},{"id":135,"depth":716,"text":136},{"id":241,"depth":716,"text":242},{"id":348,"depth":716,"text":349},{"id":493,"depth":716,"text":494},{"id":518,"depth":716,"text":518},{"id":540,"depth":716,"text":541},{"id":607,"depth":719,"text":607,"children":729},[730,732,734,736,738],{"id":610,"depth":716,"text":731},"16:17 — malgn-helper-admin → Cloudflare Pages",{"id":650,"depth":716,"text":733},"16:42 — malgn-helper-api → Cloudflare Workers",{"id":668,"depth":716,"text":735},"16:50 — malgn-helper-admin → Cloudflare Pages",{"id":684,"depth":716,"text":737},"17:37 — malgn-helper-api → Cloudflare Workers",{"id":700,"depth":716,"text":739},"17:40 — malgn-helper-admin → Cloudflare Pages","md",{},true,"\u002Fhistory\u002Fhistory.20260608",{"title":5,"description":715},"history\u002Fhistory.20260608","uyRjsN4uWp_k-2h9hkP-dhW3jfiPs8UU86wICzg63PE",1780986551106]