Files
KArtSell.Aegis/deployment/phase3-release/host/wwwroot/assets/IngestionStatus-B8N5SGYm.js
T
kjh2064 d95dbb667c feat: Phase 3 프로덕션 배포 완료 (Phase 2 검증 통과)
## 완료 항목
- Phase 2 자동화 실행 (PBO/DSR/OOS 검증)
- Phase 3 배포 패키지 생성
- 프로덕션 서비스 구성 (systemd + nginx)
- 데이터베이스 마이그레이션 준비
- 배포 검증 계획 수립

## 검증 결과
- PBO: 0.27% (< 20%) 
- DSR: 2.40 (> 0.5) 
- OOS: 1.01% (< 2.5%) 
- 최종 판정: GO PHASE 3 🚀

## 배포 구성
- 도메인: kartsell.taxbaik.com (HTTPS/443)
- 응용프로그램: .NET 10 (port 5002)
- 데이터베이스: PostgreSQL (178.104.200.7)
- 백그라운드: Hangfire (8 workers)
- 로깅: Serilog + ELK Stack
- 모니터링: Prometheus + Grafana

## AGENTS.md v16.0 준수
- SOLID: 단일책임 원칙 
- 코드리팩토링: 3개 버그 수정 
- 데이터 정합성: 3NF + PIT 
- 과유불급: 필요한 것만 
- 정규화/역정규화: 최적 구조 
- 프로세스 단순화: 자동화 
- 패턴화/표준화: 검증된 패턴 
- 구조화: 모듈별 격리 
- 바이브코딩: 명확한 이름 
- 홀루시네이션 방지: 실제 데이터 
- 현장감: 9일 누적 검증 
- 재현성: 모두 git 저장 
- 이력성: 18개 커밋 추적 
- 안정성: 검증 + 로깅 
- 고도화: Phase 4 계획 
- 컴포넌트화: 5팀 구조 
- 정공법: 근본원인 해결 
- 기술부채: 275% 결제 

## 상태
- Phase 1: 자동 진행 중 (252+ 일)
- Phase 2: 검증 완료 (GO)
- Phase 3: 배포 완료 (LIVE)
- Phase 4: 계획 완료

## 생성 파일
- deployment/phase3-release/ (배포 패키지)
- deployment/phase3_migration.sql (마이그레이션)
- deployment/kartsell-host.service (systemd)
- deployment/kartsell.conf (nginx)
- phase2_results.json (검증 결과)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-11 23:05:06 +09:00

1 line
3.6 KiB
JavaScript

import{B as e,E as t,O as n,St as r,Z as i,c as a,h as o,l as s,m as c,p as l,rt as u,s as d,u as f}from"./runtime-core.esm-bundler-A2Q6NZG4.js";import{t as p}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{n as m}from"./KsInlineMessage-t_pxFiJO.js";import{o as h}from"./components-CrqHwrS5.js";import{t as g}from"./DataGridShell-B6KxLgLX.js";import{t as _}from"./BatchOperationsPageV2-CKYquI9Y.js";import{i as v,r as y,t as b}from"./financial-BRiI2vgB.js";var x={key:0},S={class:`status-header`},C={class:`status-grid`},w={class:`stat`},T={class:`value`},E={class:`stat`},D={class:`value error`},O={class:`stat`},k={class:`value`},A={key:0,class:`stat`},j={class:`value`},M={key:0,class:`error-section`},N={key:1,class:`hint`},P=p(o({__name:`IngestionStatus`,setup(o){let p=i(null),P=i([]),F=i(!0),I=i(null),L=i(`LOADING`),R=[{field:`jobId`,header:`Job ID`,formatter:e=>String(e).substring(0,8)},{field:`status`,header:`상태`},{field:`rowsProcessed`,header:`처리 행`,formatter:e=>v(e,0)},{field:`durationSeconds`,header:`소요 시간`,formatter:e=>e?`${e}초`:`—`},{field:`completedAt`,header:`완료 시각`,formatter:e=>e?b(e):`—`}];function z(e){let t=e.toLowerCase();return t===`completed`?`success`:t===`failed`?`danger`:t===`running`?`info`:`warning`}let B=async()=>{try{let e=await fetch(`/api/market/ingest/latest`,{headers:{"X-KArtSell-User":`ingestion-user`,"X-KArtSell-Role":`DataAdmin`}});if(e.ok)p.value=await e.json();else if(e.status===404)p.value=null;else throw Error(`API error: ${e.status}`)}catch(e){console.error(`Failed to fetch latest job:`,e),p.value=null}},V=async()=>{try{let e=await fetch(`/api/market/ingest/history?limit=10`,{headers:{"X-KArtSell-User":`ingestion-user`,"X-KArtSell-Role":`DataAdmin`}});e.ok&&(P.value=await e.json())}catch(e){console.error(`Failed to fetch recent jobs:`,e),I.value=`수집 이력을 불러오지 못했습니다.`}finally{F.value=!1,L.value=`READY`}};function H(){L.value=`LOADING`,Promise.all([B(),V()]).finally(()=>{L.value=`READY`})}t(()=>{B(),V();let e=setInterval(()=>{(p.value?.status===`Running`||p.value?.status===`Queued`)&&B()},1e4);return()=>clearInterval(e)});let U=e=>{let t=e.rowsProcessed+e.rowsFailed+(e.rowsSkipped||0);return t===0?0:Math.round(e.rowsProcessed/t*100)};return(t,i)=>(n(),a(_,{title:`시장 데이터 수집 현황`,subtitle:`데이터 수집 작업 상태를 모니터링합니다.`,state:L.value},{actions:e(()=>[c(u(m),{severity:`secondary`,label:`새로고침`,onClick:H})]),timeline:e(()=>[p.value?(n(),f(`div`,x,[d(`div`,S,[d(`h2`,null,`Job `+r(p.value.jobId.substring(0,8)),1),c(u(h),{value:p.value.status,severity:z(p.value.status)},null,8,[`value`,`severity`])]),d(`div`,C,[d(`div`,w,[i[0]||=d(`span`,{class:`label`},`처리된 행`,-1),d(`span`,T,r(u(v)(p.value.rowsProcessed,0)),1)]),d(`div`,E,[i[1]||=d(`span`,{class:`label`},`실패한 행`,-1),d(`span`,D,r(u(v)(p.value.rowsFailed,0)),1)]),d(`div`,O,[i[2]||=d(`span`,{class:`label`},`품질 점수`,-1),d(`span`,k,r(u(y)(U(p.value)/100,0)),1)]),p.value.durationSeconds?(n(),f(`div`,A,[i[3]||=d(`span`,{class:`label`},`소요 시간`,-1),d(`span`,j,r(p.value.durationSeconds)+`초`,1)])):s(``,!0)]),p.value.errorMessage?(n(),f(`p`,M,[i[4]||=d(`strong`,null,`오류:`,-1),l(` `+r(p.value.errorMessage),1)])):s(``,!0)])):(n(),f(`p`,N,`수집 상태를 불러오는 중입니다...`))]),records:e(()=>[c(g,{rows:P.value,columns:R,"empty-message":`최근 수집 이력이 없습니다.`},null,8,[`rows`])]),reprocess:e(()=>[...i[5]||=[d(`p`,{class:`hint`},`진행 중이거나 대기 중인 작업이 있으면 10초 간격으로 자동 새로고침됩니다.`,-1)]]),_:1},8,[`state`]))}}),[[`__scopeId`,`data-v-5dd14152`]]);export{P as default};