Compare commits

...

6 Commits

Author SHA1 Message Date
kjh2064 8e296c2958 docs: make WBS procedure the default workflow (AEG-X-001)
ci / backend (push) Failing after 1s
ci / publish (push) Has been cancelled
ci / static (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / backend (pull_request) Failing after 1s
ci / publish (pull_request) Has been cancelled
ci / static (pull_request) Has been cancelled
ci / frontend (pull_request) Has been cancelled
Build & Test with Secrets / build (pull_request) Failing after 1s
Build & Test with Secrets / security-scan (pull_request) Has been cancelled
Build & Test with Secrets / notification (pull_request) Has been cancelled
Build & Test with Secrets / frontend (pull_request) Has been cancelled
2026-08-06 14:08:15 +09:00
kjh2064 f9762cf604 Merge pull request 'feat: add wbs and component catalogue workspace' (#7) from agent/wbs-component-catalogue into main
ci / static (push) Has been cancelled
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / publish (push) Has been cancelled
Build & Test with Secrets / build (push) Has been cancelled
Build & Test with Secrets / frontend (push) Has been cancelled
Build & Test with Secrets / security-scan (push) Has been cancelled
Build & Test with Secrets / notification (push) Has been cancelled
deploy / deploy (push) Has been cancelled
deploy / notify (push) Has been cancelled
2026-08-06 14:03:45 +09:00
kjh2064 021ca5aa13 feat: add wbs and component catalogue workspace
ci / static (push) Failing after 10s
ci / backend (push) Failing after 1s
ci / static (pull_request) Failing after 10s
ci / backend (pull_request) Failing after 0s
ci / publish (push) Has been cancelled
ci / frontend (push) Has been cancelled
Build & Test with Secrets / build (pull_request) Failing after 1s
ci / publish (pull_request) Has been cancelled
ci / frontend (pull_request) Has been cancelled
Build & Test with Secrets / notification (pull_request) Has been cancelled
Build & Test with Secrets / security-scan (pull_request) Has been cancelled
Build & Test with Secrets / frontend (pull_request) Has been cancelled
2026-08-06 14:03:21 +09:00
kjh2064 158bd90f77 Merge pull request 'ci: fail fast with backend hang evidence' (#6) from agent/ci-hang-evidence into main
ci / static (push) Has been cancelled
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / publish (push) Has been cancelled
Build & Test with Secrets / build (push) Failing after 1s
Build & Test with Secrets / security-scan (push) Failing after 7s
Build & Test with Secrets / notification (push) Has been cancelled
Build & Test with Secrets / frontend (push) Has been cancelled
deploy / notify (push) Has been cancelled
deploy / deploy (push) Has been cancelled
2026-08-06 14:02:58 +09:00
kjh2064 9b1716dd29 ci: fail fast with backend hang evidence
ci / backend (push) Failing after 0s
ci / static (push) Failing after 8s
ci / backend (pull_request) Failing after 1s
ci / static (pull_request) Failing after 8s
Build & Test with Secrets / build (pull_request) Failing after 1s
ci / frontend (push) Successful in 3m49s
Build & Test with Secrets / security-scan (pull_request) Failing after 8s
ci / frontend (pull_request) Successful in 3m48s
Build & Test with Secrets / frontend (pull_request) Successful in 3m47s
ci / publish (push) Has been skipped
ci / publish (pull_request) Has been skipped
Build & Test with Secrets / notification (pull_request) Failing after 1s
2026-08-06 14:02:39 +09:00
kjh2064 036a4e8b80 Merge pull request 'fix: restore clock and validation contracts' (#5) from agent/restore-clock-contract-build into main
ci / static (push) Has been cancelled
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / publish (push) Has been cancelled
Build & Test with Secrets / frontend (push) Has been cancelled
Build & Test with Secrets / security-scan (push) Has been cancelled
Build & Test with Secrets / notification (push) Has been cancelled
deploy / notify (push) Successful in 1s
Build & Test with Secrets / build (push) Has been cancelled
deploy / deploy (push) Successful in 1m1s
2026-08-06 13:39:58 +09:00
7 changed files with 50 additions and 3 deletions
+4 -1
View File
@@ -54,7 +54,10 @@ jobs:
- run: dotnet run --project src/KArtSell.DbMigrator -c Release --no-build
env:
KARTSELL_POSTGRES: Host=localhost;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell
- run: dotnet test KArtSell.sln --no-build -c Release --logger trx
- name: Run backend tests with hang evidence
run: >-
dotnet test KArtSell.sln --no-build -c Release --logger trx
--blame-hang --blame-hang-timeout 2m
env:
KARTSELL_POSTGRES: Host=localhost;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell
+4
View File
@@ -1,5 +1,9 @@
# K-ArtSell Aegis AI Coding Constitution v12.0
## Default execution procedure
All work in this repository MUST follow `docs/CURRENT/WBS_EXECUTION_PROCEDURES.md` as the default operating procedure, together with this constitution. Before editing, select exactly one WBS item from `docs/CURRENT/CATALOGS/WBS_MASTER.csv`, verify dependencies, Gate, Requirement/API/DB/Job/UI/Test IDs, Acceptance_Evidence, and Artifact. Record Source / Assumption / Unknown / Decision Required, then execute, collect actual evidence, update `WBS_PROGRESS_TRACKER.csv`, and commit with the WBS_ID. Do not mark a WBS item COMPLETED or claim a test/build/migration result without preserved execution evidence.
1. 자동주문과 KIS 제출 Capability는 OFF다. 별도 승인 Release 전 구현·활성화·우회하지 않는다.
2. 채팅과 생성 코드는 Source of Truth가 아니다. 모든 변경은 Source / Assumption / Unknown / Decision Required를 표시한다.
3. 한 PR은 한 Vertical Slice 또는 한 동작보존 리팩터링 목적만 가진다.
+1
View File
@@ -8,6 +8,7 @@ import { AppShellLayout } from './shared/ui/layouts'
<section><h2>Research</h2><RouterLink to="/research/sell-decision">매도 의사결정</RouterLink></section>
<section><h2>Portfolio</h2><RouterLink to="/portfolio/risk">포트폴리오 리스크</RouterLink><RouterLink to="/portfolio/rebalance">리밸런싱 제안</RouterLink></section>
<section><h2>Operations</h2><RouterLink to="/ops/data-quality">데이터 품질</RouterLink><RouterLink to="/ops/market-data-ingestion">시장 데이터 수집</RouterLink><RouterLink to="/ops/market-data-history">수집 이력</RouterLink><RouterLink to="/ops/model-operations">모델 운영</RouterLink></section>
<section><h2>Internal</h2><RouterLink to="/internal/wbs">WBS 작업공간</RouterLink><RouterLink to="/internal/ui-standard">컴포넌트 카탈로그</RouterLink></section>
</nav></template>
<RouterView />
</AppShellLayout>
+3 -1
View File
@@ -3,6 +3,7 @@ import SellDecisionPage from '../features/sell-decision/pages/SellDecisionPage.v
import DataQualityPage from '../features/data-quality/pages/DataQualityPage.vue'
import ModelOperationsPage from '../features/model-operations/pages/ModelOperationsPage.vue'
import UiStandardPage from '../features/ui-standard/pages/UiStandardPage.vue'
import WbsWorkspacePage from '../features/wbs/pages/WbsWorkspacePage.vue'
import RiskDashboard from '../features/portfolio/pages/RiskDashboard.vue'
import RebalanceForm from '../features/portfolio/pages/RebalanceForm.vue'
import MarketDataIngestion from '../features/marketData/pages/MarketDataIngestion.vue'
@@ -19,6 +20,7 @@ export const router = createRouter({
{ path: '/ops/market-data-history', component: IngestionStatus, meta: { screenId: 'SCR-017', templateId: 'T08' } },
{ path: '/portfolio/risk', component: RiskDashboard, meta: { screenId: 'SCR-018', templateId: 'T07' } },
{ path: '/portfolio/rebalance', component: RebalanceForm, meta: { screenId: 'SCR-019', templateId: 'T03' } },
{ path: '/internal/ui-standard', component: UiStandardPage, meta: { screenId: 'SCR-DEV-001', templateId: 'T01', internalOnly: true } }
{ path: '/internal/ui-standard', component: UiStandardPage, meta: { screenId: 'SCR-DEV-001', templateId: 'T01', internalOnly: true } },
{ path: '/internal/wbs', component: WbsWorkspacePage, meta: { screenId: 'SCR-DEV-002', templateId: 'T01', internalOnly: true } }
]
})
@@ -19,7 +19,15 @@ const columns: UiGridColumn[] = [{ field: 'id', header: '화면 ID', width: 100
<template #summary><div class="ks-card summary"><strong>10</strong><span>화면 타입</span></div><div class="ks-card summary"><strong>{{ adapter.descriptor.capabilities.size }}</strong><span>어댑터 포트</span></div><div class="ks-card summary"><KsStatusTag :value="adapter.descriptor.id" severity="info" /><span>{{ adapter.descriptor.vendor }}</span></div><div class="ks-card summary"><KsStatusTag value="자동주문 OFF" severity="warning" /><span>고정 경계</span></div></template>
<template #filters><div class="filters"><KsTextField v-model="query" label="검색" placeholder="화면 ID, 타입 또는 컴포넌트" /><KsSelect v-model="status" label="상태" :options="options" /></div></template>
<KsDataGrid :rows="rows" :columns="columns" height="25rem" />
<section class="ks-card component-preview" aria-labelledby="component-preview-title">
<div><h2 id="component-preview-title">컴포넌트 동작 프리뷰</h2><p>공유 UI 포트를 실제 상태로 확인하는 내부 전용 카탈로그입니다.</p></div>
<div class="preview-grid">
<div><h3>Actions</h3><KsButton label="기본 버튼" severity="secondary" /><KsButton label="주의 상태" severity="warning" /></div>
<div><h3>Status</h3><div class="status-row"><KsStatusTag value="READY" severity="success" /><KsStatusTag value="REVIEW" severity="warning" /><KsStatusTag value="BLOCKED" severity="danger" /></div></div>
<div><h3>Inputs</h3><KsTextField label="텍스트 필드" model-value="샘플 " /><KsSelect label="선택 필드" model-value="READY" :options="[{ label: '준비', value: 'READY' }, { label: '검토', value: 'REVIEW' }]" /></div>
</div>
</section>
<template #detail><div class="ks-card detail"><h2>교체 계약</h2><p>기본 공급자 교체는 <code>VITE_UI_ADAPTER</code> provider registry에서 수행한다. Feature 코드는 변경하지 않는다.</p><p>PrimeVue+AG Grid와 Native reference adapter가 동일 contract test를 통과해야 한다.</p><p>생산 교체는 접근성, 키보드, 상태행렬, 시각회귀, 대량목록 성능을 별도 Gate로 검증한다.</p></div></template>
</SearchListCrudPage>
</template>
<style scoped>.filters{display:grid;grid-template-columns:2fr 1fr;gap:var(--ks-space-3)}.summary,.detail{padding:var(--ks-space-4)}.summary{display:grid;gap:var(--ks-space-1)}.summary strong{font-size:1.5rem}.detail h2{margin-top:0;font-size:var(--ks-font-section)}@media(max-width:700px){.filters{grid-template-columns:1fr}}</style>
<style scoped>.filters{display:grid;grid-template-columns:2fr 1fr;gap:var(--ks-space-3)}.summary,.detail,.component-preview{padding:var(--ks-space-4)}.summary{display:grid;gap:var(--ks-space-1)}.summary strong{font-size:1.5rem}.detail h2,.component-preview h2{margin-top:0;font-size:var(--ks-font-section)}.preview-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--ks-space-4)}.preview-grid>div{display:grid;align-content:start;gap:var(--ks-space-2);padding:var(--ks-space-3);border:1px solid var(--ks-color-neutral-200);border-radius:var(--ks-radius-sm)}.preview-grid h3{margin:0;font-size:var(--ks-font-caption)}.status-row{display:flex;flex-wrap:wrap;gap:var(--ks-space-2)}@media(max-width:700px){.filters,.preview-grid{grid-template-columns:1fr}}</style>
@@ -0,0 +1,24 @@
<script setup lang="ts">
import { ref } from 'vue'
import { KsStatusTag } from '@/shared/ui/components'
type WbsItem = { id: string; title: string; owner: string; state: 'DONE' | 'IN_PROGRESS' | 'DECISION_REQUIRED' }
const selectedId = ref('UI-001')
const items: WbsItem[] = [
{ id: 'UI-001', title: '공유 컴포넌트 카탈로그와 상태 프리뷰', owner: 'FE Platform', state: 'IN_PROGRESS' },
{ id: 'UI-002', title: 'WBS 실행 화면 및 요구사항 추적', owner: 'Delivery', state: 'IN_PROGRESS' },
{ id: 'DATA-001', title: 'DB 스키마 Read Model/API 계약', owner: 'Data Platform', state: 'DECISION_REQUIRED' },
{ id: 'OPS-001', title: 'Playwright 시각·상태행렬 검증', owner: 'QA', state: 'IN_PROGRESS' },
]
</script>
<template>
<section class="page" aria-labelledby="wbs-title">
<header class="page-header"><div><p class="eyebrow">INTERNAL · READ ONLY</p><h1 id="wbs-title">WBS 실행공간</h1><p>요구사항·Slice·검증 상태를 화면에서 추적합니다. 화면은 작업을 자동 실행하거나 배포하지 않습니다.</p></div><KsStatusTag value="AUTOMATION OFF" severity="warning" /></header>
<div class="summary-grid"><div class="ks-card"><strong>4</strong><span>현재 Slice</span></div><div class="ks-card"><strong>1</strong><span>Decision Required</span></div><div class="ks-card"><strong>UI-CONTRACT-4.0</strong><span>계약 버전</span></div></div>
<div class="workspace">
<section class="ks-card list" aria-labelledby="wbs-list-title"><h2 id="wbs-list-title">작업 목록</h2><button v-for="item in items" :key="item.id" class="wbs-row" :class="{ selected: selectedId === item.id }" type="button" @click="selectedId = item.id"><span><b>{{ item.id }}</b>{{ item.title }}</span><small>{{ item.owner }}</small><KsStatusTag :value="item.state" :severity="item.state === 'DONE' ? 'success' : item.state === 'DECISION_REQUIRED' ? 'danger' : 'info'" /></button></section>
<section class="ks-card detail" aria-labelledby="wbs-detail-title"><h2 id="wbs-detail-title">선택 작업 증거</h2><template v-if="selectedId === 'DATA-001'"><p class="warning">서버 Read Model, 권한 정책, PIT 범위가 승인되기 전에는 DB 스키마를 직접 노출하지 않습니다.</p><dl><dt>필요 계약</dt><dd>API/DB/Role/Projection Version</dd><dt>상태</dt><dd>DECISION_REQUIRED</dd></dl></template><template v-else><p>현재 작업은 내부 검토용이며, 구현·테스트·스크린샷 증거를 Slice 기록에 연결해야 합니다.</p><dl><dt>Slice</dt><dd>{{ selectedId }}</dd><dt>자동주문/KIS</dt><dd>OFF</dd><dt>검증</dt><dd>Playwright 실행 증거화 예정</dd></dl></template></section>
</div>
</section>
</template>
<style scoped>.page{display:grid;gap:var(--ks-space-5)}.page-header{display:flex;justify-content:space-between;gap:var(--ks-space-4);align-items:start}.eyebrow{font-size:var(--ks-font-caption);color:var(--ks-color-neutral-600);letter-spacing:.08em}.page-header h1{margin:.25rem 0}.summary-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--ks-space-3)}.summary-grid .ks-card{display:grid;gap:.25rem;padding:var(--ks-space-4)}.summary-grid strong{font-size:1.35rem}.summary-grid span{color:var(--ks-color-neutral-600)}.workspace{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(18rem,.75fr);gap:var(--ks-space-4)}.list,.detail{padding:var(--ks-space-4)}.list h2,.detail h2{margin-top:0}.wbs-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:var(--ks-space-3);width:100%;padding:var(--ks-space-3);border:0;border-top:1px solid var(--ks-color-neutral-200);background:#fff;text-align:left;cursor:pointer}.wbs-row span{display:grid;gap:.25rem}.wbs-row b{font-size:var(--ks-font-caption);color:var(--ks-color-primary-700)}.wbs-row small{color:var(--ks-color-neutral-600)}.wbs-row.selected{background:var(--ks-color-neutral-100)}.warning{padding:var(--ks-space-3);border-left:3px solid #d97706;background:#fffbeb}.detail dl{display:grid;grid-template-columns:auto 1fr;gap:var(--ks-space-2);font-size:var(--ks-font-caption)}.detail dt{font-weight:700}.detail dd{margin:0}@media(max-width:800px){.workspace,.summary-grid{grid-template-columns:1fr}.page-header{flex-direction:column}.wbs-row{grid-template-columns:1fr auto}}</style>
@@ -1,5 +1,6 @@
<script setup lang="ts">
defineProps<{ productName?: string; environment?: string; automationStatus?: string }>()
const appVersion = import.meta.env.VITE_APP_VERSION ?? '0.1.0'
</script>
<template>
<div class="ks-shell">
@@ -12,6 +13,9 @@ defineProps<{ productName?: string; environment?: string; automationStatus?: str
<aside class="ks-shell__nav" aria-label="주요 메뉴"><slot name="navigation" /></aside>
<main id="ks-main" class="ks-shell__main" tabindex="-1"><slot /></main>
<footer class="ks-shell__footer"><slot name="footer">RESEARCH_CANDIDATE_NOT_PRODUCTION</slot></footer>
<div class="ks-shell__version" data-testid="app-version" aria-label="애플리케이션 버전">
v{{ appVersion }} · UI contract 4.0
</div>
</div>
</template>
<style scoped>
@@ -22,6 +26,7 @@ defineProps<{ productName?: string; environment?: string; automationStatus?: str
.ks-shell__nav { grid-area: nav; padding: var(--ks-space-4); border-right: 1px solid var(--ks-color-neutral-200); background: #fff; }
.ks-shell__main { grid-area: main; min-width: 0; padding: var(--ks-space-6); }
.ks-shell__footer { grid-area: footer; padding: var(--ks-space-2) var(--ks-space-6); border-top: 1px solid var(--ks-color-neutral-200); background: #fff; color: var(--ks-color-neutral-600); font-size: var(--ks-font-caption); }
.ks-shell__version { position: fixed; left: var(--ks-space-3); bottom: var(--ks-space-2); z-index: 20; padding: .25rem .5rem; border: 1px solid var(--ks-color-neutral-200); border-radius: var(--ks-radius-sm); background: rgb(255 255 255 / 92%); color: var(--ks-color-neutral-600); font-size: .7rem; box-shadow: 0 .15rem .5rem rgb(15 23 42 / 8%); }
.ks-skip { position: fixed; left: var(--ks-space-2); top: -4rem; z-index: 1000; padding: var(--ks-space-2); background: #fff; } .ks-skip:focus { top: var(--ks-space-2); }
@media (max-width: 900px) { .ks-shell { grid-template-columns: 1fr; grid-template-areas: 'header' 'nav' 'main' 'footer'; } .ks-shell__header { align-items: flex-start; flex-direction: column; } .ks-shell__nav { border-right: 0; border-bottom: 1px solid var(--ks-color-neutral-200); } }
</style>