Files
KArtSell.Aegis/deployment/phase3-release/host/wwwroot/assets/UiStandardPage-DDdclLD6.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
8.5 KiB
JavaScript

import{A as e,Ct as t,D as n,Y as r,c as i,f as a,h as o,m as s,o as c,p as l,s as u,tt as d,z as f}from"./runtime-core.esm-bundler-DJThmTxA.js";import{t as p}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as m}from"./ReviewWorkbenchLayout-CU1nbEwk.js";import{n as h}from"./useUiAdapter-Dhcoyf0S.js";import{n as g}from"./KsInlineMessage-Cl9GruP-.js";import{i as _,n as v,r as y,t as b}from"./components-BwWzTICE.js";import{t as x}from"./QueryStateBoundary-BJDsqvSq.js";var S=o({__name:`StandardScreenBoundary`,props:{state:{default:`READY`},warning:{},error:{},staleAt:{},correlationId:{}},emits:[`retry`],setup(t,{emit:r}){let a=r;return(r,o)=>(n(),i(x,{loading:t.state===`LOADING`,processing:t.state===`PROCESSING`,dirty:t.state===`DIRTY`,empty:t.state===`EMPTY`,partial:t.state===`PARTIAL`,unauthorized:t.state===`UNAUTHORIZED`,forbidden:t.state===`FORBIDDEN`,conflict:t.state===`CONFLICT`,expired:t.state===`EXPIRED`,readonly:t.state===`READONLY`,warning:t.state===`WARN`?t.warning:void 0,error:t.state===`ERROR`?t.error??Error(`화면 상태 오류`):void 0,"stale-at":t.staleAt,"correlation-id":t.correlationId,onRetry:o[0]||=e=>a(`retry`)},{default:f(()=>[e(r.$slots,`default`)]),_:3},8,[`loading`,`processing`,`dirty`,`empty`,`partial`,`unauthorized`,`forbidden`,`conflict`,`expired`,`readonly`,`warning`,`error`,`stale-at`,`correlation-id`]))}}),C=o({__name:`SearchListCrudPage`,props:{title:{},subtitle:{},state:{},evidence:{},warning:{},error:{}},emits:[`retry`],setup(t){let r=t;return(t,o)=>(n(),i(m,{title:r.title,subtitle:r.subtitle,status:r.state,"as-of":r.evidence?.asOf,version:r.evidence?.version},a({actions:f(()=>[e(t.$slots,`actions`)]),summary:f(()=>[e(t.$slots,`summary`)]),filters:f(()=>[e(t.$slots,`filters`)]),default:f(()=>[s(S,{state:r.state,warning:r.warning,"stale-at":r.evidence?.asOf,onRetry:o[0]||=e=>t.$emit(`retry`)},{default:f(()=>[e(t.$slots,`default`)]),_:3},8,[`state`,`warning`,`stale-at`])]),_:2},[t.$slots.detail?{name:`aside`,fn:f(()=>[e(t.$slots,`detail`)]),key:`0`}:void 0,t.$slots.footer?{name:`footer`,fn:f(()=>[e(t.$slots,`footer`)]),key:`1`}:void 0]),1032,[`title`,`subtitle`,`status`,`as-of`,`version`]))}}),w=Object.freeze([{id:`T01`,name:`검색·목록형 CRUD`,component:`SearchListCrudPage`,intendedUse:`상품·고객·권한·데이터 Run·추천 검토함`,mandatoryStates:[`READY`,`LOADING`,`EMPTY`,`WARN`,`ERROR`,`UNAUTHORIZED`,`FORBIDDEN`,`PARTIAL`],mandatoryEvidence:[`filter-url`,`permission`,`export-auth`],antiPatterns:[`client-side-all-data`,`unbounded-export`]},{id:`T02`,name:`상세 조회형`,component:`DetailReadPage`,intendedUse:`투자제안·상품·포트폴리오·백테스트 결과`,mandatoryStates:[`LOADING`,`WARN`,`EXPIRED`,`READONLY`,`UNAUTHORIZED`],mandatoryEvidence:[`as-of`,`version-set`,`audit`],antiPatterns:[`mutable-evidence`,`hidden-version`]},{id:`T03`,name:`등록·편집 Form`,component:`EditFormPage`,intendedUse:`고객·IPS·비용표·권한·설정`,mandatoryStates:[`DIRTY`,`CONFLICT`,`PROCESSING`,`ERROR`],mandatoryEvidence:[`zod`,`if-match`,`idempotency-key`],antiPatterns:[`silent-overwrite`,`pinia-form-cache`]},{id:`T04`,name:`Master-Detail`,component:`MasterDetailCrudPage`,intendedUse:`고객-IPS·추천-항목·Watch-Stage·대사 Run-Break`,mandatoryStates:[`LOADING`,`EMPTY`,`DIRTY`,`PARTIAL`,`CONFLICT`],mandatoryEvidence:[`route-selection`,`unsaved-guard`,`version`],antiPatterns:[`selection-only-local`,`detail-n-plus-one`]},{id:`T05`,name:`검토·승인 Workbench`,component:`ApprovalWorkbenchPage`,intendedUse:`추천·모델·정정·대사 maker-checker`,mandatoryStates:[`WARN`,`EXPIRED`,`CONFLICT`,`PROCESSING`,`READONLY`],mandatoryEvidence:[`maker-checker`,`reason`,`warning-ack`],antiPatterns:[`self-approval`,`approval-without-evidence`]},{id:`T06`,name:`단계 Wizard`,component:`StepWizardPage`,intendedUse:`고객 온보딩·IPS·리밸런싱·Backfill`,mandatoryStates:[`DIRTY`,`ERROR`,`PROCESSING`,`READONLY`],mandatoryEvidence:[`resume`,`branch`,`impact-revalidation`],antiPatterns:[`single-huge-form`,`skip-validation`]},{id:`T07`,name:`Dashboard·Scorecard`,component:`ScorecardDashboardPage`,intendedUse:`고객 대시보드·일평가·운영 SLO`,mandatoryStates:[`LOADING`,`EMPTY`,`WARN`,`PARTIAL`],mandatoryEvidence:[`metric-definition`,`sample-size`,`table-alternative`],antiPatterns:[`chart-only`,`metric-definition-hidden`]},{id:`T08`,name:`Batch·데이터 운영`,component:`BatchOperationsPageV2`,intendedUse:`수집·Feature·추천·평가·Backfill`,mandatoryStates:[`PROCESSING`,`WARN`,`ERROR`,`PARTIAL`,`READONLY`],mandatoryEvidence:[`job-run`,`watermark`,`replay-scope`],antiPatterns:[`blind-retry`,`overwrite-reprocess`]},{id:`T09`,name:`대사·예외 처리`,component:`ReconciliationExceptionPage`,intendedUse:`KIS/원장 대사·데이터 격리·DQ 예외`,mandatoryStates:[`WARN`,`CONFLICT`,`PROCESSING`,`READONLY`],mandatoryEvidence:[`before-after`,`correction`,`audit`],antiPatterns:[`direct-db-fix`,`delete-break`]},{id:`T10`,name:`버전 비교·거버넌스`,component:`VersionGovernancePage`,intendedUse:`모델·정책·설정·데이터 공급원 승격`,mandatoryStates:[`WARN`,`EXPIRED`,`READONLY`,`CONFLICT`],mandatoryEvidence:[`same-dataset-cost`,`gate-pack`,`rollback`],antiPatterns:[`auto-promotion`,`different-cohort-comparison`]}]),T={class:`ks-card summary`},E={class:`ks-card summary`},D={class:`ks-card summary`},O={class:`filters`},k={class:`ks-card component-preview`,"aria-labelledby":`component-preview-title`},A={class:`preview-grid`},j={class:`status-row`},M=p(o({__name:`UiStandardPage`,setup(e){let a=h(),o=r(``),p=r(`ALL`),m=[{label:`전체`,value:`ALL`},{label:`검토 필요`,value:`REVIEW`},{label:`보류`,value:`HOLD`}],x=c(()=>w.filter(e=>!o.value||`${e.id} ${e.name} ${e.component}`.toLowerCase().includes(o.value.toLowerCase())).map(e=>({id:e.id,name:e.name,component:e.component,evidence:e.mandatoryEvidence.length,state:`READY`}))),S=[{field:`id`,header:`화면 ID`,width:100},{field:`name`,header:`화면 타입`},{field:`component`,header:`표준 컴포넌트`,minWidth:220},{field:`evidence`,header:`필수 증거`,width:110},{field:`state`,header:`상태`,width:110}];return(e,r)=>(n(),i(d(C),{title:`표준 UI 패턴`,subtitle:`Feature는 공급자 라이브러리를 직접 사용하지 않고, v4 어댑터·레이아웃·화면 계약을 사용한다.`,state:`READY`,evidence:{asOf:`2026-08-02`,version:`UI-CONTRACT-4.0`}},{actions:f(()=>[s(d(g),{label:`새 화면 패킷`,severity:`secondary`})]),summary:f(()=>[r[4]||=u(`div`,{class:`ks-card summary`},[u(`strong`,null,`10`),u(`span`,null,`화면 타입`)],-1),u(`div`,T,[u(`strong`,null,t(d(a).descriptor.capabilities.size),1),r[2]||=u(`span`,null,`어댑터 포트`,-1)]),u(`div`,E,[s(d(v),{value:d(a).descriptor.id,severity:`info`},null,8,[`value`]),u(`span`,null,t(d(a).descriptor.vendor),1)]),u(`div`,D,[s(d(v),{value:`자동주문 OFF`,severity:`warning`}),r[3]||=u(`span`,null,`고정 경계`,-1)])]),filters:f(()=>[u(`div`,O,[s(d(_),{modelValue:o.value,"onUpdate:modelValue":r[0]||=e=>o.value=e,label:`검색`,placeholder:`화면 ID, 타입 또는 컴포넌트`},null,8,[`modelValue`]),s(d(y),{modelValue:p.value,"onUpdate:modelValue":r[1]||=e=>p.value=e,label:`상태`,options:m},null,8,[`modelValue`])])]),detail:f(()=>[...r[9]||=[u(`div`,{class:`ks-card detail`},[u(`h2`,null,`교체 계약`),u(`p`,null,[l(`기본 공급자 교체는 `),u(`code`,null,`VITE_UI_ADAPTER`),l(`와 provider registry에서 수행한다. Feature 코드는 변경하지 않는다.`)]),u(`p`,null,`PrimeVue+AG Grid와 Native reference adapter가 동일 contract test를 통과해야 한다.`),u(`p`,null,`생산 교체는 접근성, 키보드, 상태행렬, 시각회귀, 대량목록 성능을 별도 Gate로 검증한다.`)],-1)]]),default:f(()=>[s(d(b),{rows:x.value,columns:S,height:`25rem`},null,8,[`rows`]),u(`section`,k,[r[8]||=u(`div`,null,[u(`h2`,{id:`component-preview-title`},`컴포넌트 동작 프리뷰`),u(`p`,null,`공유 UI 포트를 실제 상태로 확인하는 내부 전용 카탈로그입니다.`)],-1),u(`div`,A,[u(`div`,null,[r[5]||=u(`h3`,null,`Actions`,-1),s(d(g),{label:`기본 버튼`,severity:`secondary`}),s(d(g),{label:`주의 상태`,severity:`warning`})]),u(`div`,null,[r[6]||=u(`h3`,null,`Status`,-1),u(`div`,j,[s(d(v),{value:`READY`,severity:`success`}),s(d(v),{value:`REVIEW`,severity:`warning`}),s(d(v),{value:`BLOCKED`,severity:`danger`})])]),u(`div`,null,[r[7]||=u(`h3`,null,`Inputs`,-1),s(d(_),{label:`텍스트 필드`,"model-value":`샘플 값`}),s(d(y),{label:`선택 필드`,"model-value":`READY`,options:[{label:`준비`,value:`READY`},{label:`검토`,value:`REVIEW`}]})])])])]),_:1}))}}),[[`__scopeId`,`data-v-b808fd06`]]);export{M as default};