Complete legacy operator UI and playout migration
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
| WinForms MainForm | WinUI 3 `MainWindow` + 로컬 WebView2 UI |
|
||||
| FarPoint `FpSpread` 플레이리스트 | HTML table + 선택/드래그 정렬/이동/삭제 |
|
||||
| 플레이리스트 임시 저장 | WebView2 사용자 데이터 영역의 `localStorage` |
|
||||
| Oracle `DC_LIST`/`PLAY_LIST` | 이름 있는 플레이리스트 생성·교체·불러오기·삭제와 fresh page preflight |
|
||||
| WinForms 단축키 | Web UI `F2` / `F8` / `Esc` 처리 |
|
||||
| 직접 DBManager 호출 | Core의 `IDataQueryExecutor` 경계 |
|
||||
| `Data/Request` SQL 정의 | .NET 8 Core 프로젝트로 71개 이관 |
|
||||
@@ -33,7 +34,7 @@
|
||||
|
||||
WebView는 `https://app.mbn.local` 가상 호스트로 패키지 내부 파일만 제공합니다. 외부 탐색은 WebView 안에서 차단하고 기본 브라우저로 넘기며, 개발자 도구와 기본 컨텍스트 메뉴는 디버거가 연결된 경우에만 활성화합니다.
|
||||
|
||||
## 다음 구현 경계
|
||||
## 구현 및 후속 운영 경계
|
||||
|
||||
### 데이터베이스
|
||||
|
||||
@@ -58,17 +59,19 @@ WebView는 `https://app.mbn.local` 가상 호스트로 패키지 내부 파일
|
||||
- 완료: 네이티브/Interop 이중 SHA-256 핀, 프로세스 수명 파일 잠금, 실제 PGM listener 소유권 및 KTAP 지연 dispatch 차단
|
||||
- 과거 기본 경로 증거: 승인된 PGM 고정 runner에서 `5001 → 5006 → TAKE OUT`과 Network Monitoring `HELLO/LOAD_SCENE/SCENE_PREPARE/PLAY/STOPAL/BYE`, 39개 연속 캡처를 검증했다. 이는 현재 WebView의 fresh TAKE IN, Page NEXT, timer refresh 또는 35개 builder 동등성 완료 증거가 아니다.
|
||||
- 완료: 첫 과거 회차의 출력 전 Prepare 거부 원인이 cue 이중 resolve임을 확인하고, 상대 cue와 승인 검사용 절대 자산 경로를 분리하는 수정 및 회귀 테스트 적용. 결과 불명확 시 재시도 금지 원칙 유지
|
||||
- 현재 목표 미완료: 승인 회차 `MBNWEB-20260711-A`에서 설치된 MSIX WebView의 CONNECT와 `PREPARE 5001/page 1` 및 Network Monitoring transaction/mutation/SCENE_PREPARE는 성공했다. 그러나 fresh TAKE IN의 Oracle 조회가 K3D PLAY 전에 `DATABASE_UNAVAILABLE`로 명확히 실패해 재시도하지 않았고, STOPAL/UNLOAD/BYE로 안전하게 회수했다. 회차 종료 뒤 Oracle/MariaDB 전체 스모크는 다시 통과했지만 새 회차에서 `fresh TAKE IN → playlist/Page NEXT → timer refresh → TAKE OUT`과 PGM 동시 검증을 통과해야 한다.
|
||||
- 과거 실패·복구 증거: 승인 회차 `MBNWEB-20260711-A`의 CONNECT/PREPARE 뒤 fresh TAKE IN Oracle 조회가 K3D PLAY 전에 명확히 실패했으며 재시도 없이 STOPAL/UNLOAD/BYE로 회수했다.
|
||||
- 승인 범위 완료: 이후 `MBNWEB-20260711-H`에서 설치된 MSIX WebView로 `5001 PREPARE → fresh TAKE IN → 자동 refresh 1회 → 5074 playlist NEXT → Page NEXT → TAKE OUT`을 실제 PGM과 Network Monitoring에서 함께 확인했다. `PLAY=4`, `SCENE_PLAYED=4`, FAILURE/ERROR/retry=0, 최종 `OutcomeUnknown=false`였다. 이 증거는 승인된 `5001`/`5074`에만 적용한다.
|
||||
- 완료: `OnScenePlayed`/`OnCutOut`/`OnStopAll` callback 기반 장기 세션 Scene unload와 pending callback fail-closed accounting
|
||||
- 완료: 35개 scene builder의 복합 K3D mutation 및 `PageN`/`Nxt_PageN` 5·6·12개/최대 20페이지 포팅과 자동·실제 DB 검증
|
||||
|
||||
### 화면 기능
|
||||
|
||||
- Oracle 플레이리스트 영구 저장/불러오기
|
||||
- 10개 업무 탭의 실제 데이터 바인딩
|
||||
- 테마, 전문가, VI, 비교, 수동 그래프 편집기
|
||||
- 35개 장면 빌더의 실제 Tornado2/PGM 화면 동등성 회차 검증
|
||||
- 실제 Preview 이미지 및 씬/영상 자산 연결
|
||||
- 완료: MainForm과 UC1~UC7의 종목·고정·업종·비교·테마·해외·전문가·거래정지 workflow
|
||||
- 완료: GraphE, FSell, VIList, PList/AList, ThemeA, EList 전용 화면과 native bridge
|
||||
- 완료: 328 fixed + 44 industry + 31 stock + 9 comparison의 412 action 자동 매트릭스
|
||||
- 완료: F2/F3 배경 선택, 전역 5일선/20일선, 이름 있는 Oracle 플레이리스트
|
||||
- 후속 승인 범위: `5001`/`5074` 이외 장면의 실제 Tornado2/PGM 확인
|
||||
- 후속 운영 자산: 필요할 때 trusted scene-root의 실제 Preview 이미지 및 영상 연결
|
||||
|
||||
## 의도적으로 제외한 항목
|
||||
|
||||
|
||||
280
docs/OPERATOR_UI_PARITY.md
Normal file
280
docs/OPERATOR_UI_PARITY.md
Normal file
@@ -0,0 +1,280 @@
|
||||
# 운영자 UI 동등성 인벤토리
|
||||
|
||||
## 문서 목적과 판정 기준
|
||||
|
||||
이 문서는 원본 WinForms 운영 화면의 사용자 동작을 새 WinUI 3/WebView 구현에 1:1로 연결한다. 장면 builder가 존재하는 것, 네이티브 bridge와 workflow 모듈이 존재하는 것, 실제 Web 화면에서 운영자가 사용할 수 있는 것은 서로 다른 완료 조건으로 취급한다.
|
||||
|
||||
상태 표기는 다음과 같다.
|
||||
|
||||
| 상태 | 의미 |
|
||||
|---|---|
|
||||
| 화면 통합 완료 | 현재 `Web/index.html`과 `Web/app.js`에서 검색·선택·플레이리스트 추가 또는 저장 동작을 실행할 수 있다. |
|
||||
| 화면 통합 완료 / 실환경 검증 대기 | Web 화면, native bridge, workflow와 자동 테스트까지 연결됐지만 운영 DB write 또는 해당 경로의 실제 PGM 확인은 수행하지 않았다. |
|
||||
| 일부 검증 | 화면 동작은 구현됐지만 해당 기능 전체를 실제 운영 DB write 또는 PGM으로 확인하지 않았다. |
|
||||
|
||||
`DB-W`는 운영 데이터베이스에 실제 쓰기를 수행해 확인했는지를 뜻한다. `PGM`은 실제 Tornado2 PGM 출력으로 해당 UI 경로를 확인했는지를 뜻한다. fake executor, DryRun, SQL 계약 테스트는 자동 테스트 근거이지 실제 DB-W 또는 PGM 검증으로 계산하지 않는다.
|
||||
|
||||
## 원본 보존 상태
|
||||
|
||||
- 원본 저장소는 읽기 전용으로만 분석했고 파일을 수정하지 않았다.
|
||||
- 분석 시작 시 원본에 이미 존재하던 dirty 파일은 `MBN_STOCK_N/MainForm.cs`, `MBN_STOCK_N/RES/MmoneyCoder.ini` 두 개였다. 두 파일의 기존 변경을 그대로 보존했다.
|
||||
- 이 문서에는 비밀번호, 실제 방송 데이터, 자산·경로 해시를 기록하지 않는다.
|
||||
|
||||
## 412개 실행 action의 고정 분해
|
||||
|
||||
412는 다음 네 집합의 합이다. 동적 테마·전문가 목록과 GraphE 편집 행 수는 이 숫자에 중복해 더하지 않는다.
|
||||
|
||||
| 집합 | 원본 UI | 수량 | 새 구현 | 자동 근거 | 상태 |
|
||||
|---|---|---:|---|---|---|
|
||||
| 고정 action | `MainForm`의 해외·환율·지수 탭과 `Control/UC1.cs` | 328 | `Web/legacy-fixed-workflow.js` | `tests/Web/legacy-fixed-workflow.test.cjs`가 328개, 직접 생성 가능한 322개, 수동 전제 6개를 고정한다. | 화면 통합 완료. 수동 6개는 아래 대체 경계를 통과해야 한다. |
|
||||
| 업종 action | `Control/UC1.cs` + `Control/UC2.cs`의 코스피·코스닥 | 44 | `Web/industry-workflow.js`의 시장별 22개 | `tests/Web/industry-workflow.test.cjs` | 화면 통합 완료 |
|
||||
| 종목 action | `MainForm` 좌측 종목 검색·컷 목록 | 31 | `Web/operator-workflow.js` | `tests/Web/operator-workflow.test.cjs`가 실행 자산 순서의 31개를 고정한다. | 화면 통합 완료 |
|
||||
| 비교 action | `Control/UC1.cs` + `Control/UC3.cs` | 9 | `Web/comparison-workflow.js` | `tests/Web/comparison-workflow.test.cjs`가 24개 비교 대상과 9개 action을 별도로 고정한다. | 화면 통합 완료 |
|
||||
| 합계 | | **412** | | | |
|
||||
|
||||
고정 action 328개 안의 수동 전제 6개는 일반 고정 DTO로 임의 생성하지 않는다.
|
||||
|
||||
| 원본 고정 항목 | 수량 | 원본 전용 폼 | 새 대체 경계 | 관계 |
|
||||
|---|---:|---|---|---|
|
||||
| 개인·외국인·기관 순매도 상위(수동) | 3 | `Form/FSell.cs` | `MainWindow.ManualLists.cs`, `Web/manual-lists-workflow.js`, 신뢰된 s5025 파일 저장소 | 각 audience의 검증된 5행 입력이 있어야 `s5025/5025` 플레이리스트 항목을 만든다. |
|
||||
| 5단·6종목·12종목 섹션의 VI 발동(수동) placeholder | 3 | `Form/VIList.cs` | `MainWindow.ManualLists.cs`, `Web/manual-lists-workflow.js`, 신뢰된 VI 저장소 | 세 placeholder 모두 원본 VIList가 만든 하나의 `s5074/5074` 5행 페이지 결과로 대체된다. 6·12행 장면으로 바꾸지 않는다. |
|
||||
|
||||
현재 이 수동 6개는 FSell/VIList 대체 화면까지 통합됐다. 고정 카탈로그에서 임의 DTO로 직접 활성화하지 않고, 전용 입력 화면이 저장 후 재조회한 신뢰 데이터와 버전을 공급한 뒤에만 플레이리스트에 넣는다.
|
||||
|
||||
## 화면 단위 완료 요약
|
||||
|
||||
| 원본 화면 | 핵심 역할 | 새 화면/모듈 상태 | DB-W | 해당 UI의 PGM |
|
||||
|---|---|---|---|---|
|
||||
| MainForm | 종목 검색, 31개 컷, playlist, 송출·배경·저장 | 화면 통합 완료 | 없음/해당 없음 | 일부: 승인된 `5001`, `5074`, TAKE OUT |
|
||||
| UC1 | 328 fixed, 업종·비교 action 트리 | 전체 action과 수동 6개 전용 편집 화면 통합 완료 | 해당 없음 | 일부: generic `5074`; 전체 action 미검증 |
|
||||
| UC2 | 업종 목록과 두 업종 선택 | 화면 통합 완료 | 해당 없음 | 미검증 |
|
||||
| UC3 | 비교 대상·저장 비교쌍·9 action | 화면 통합 완료 | 원본 파일 저장을 browser schema 저장으로 대체 | 미검증 |
|
||||
| UC4 | 테마 검색·preview·5/6/12행 항목 | 조회/선택 및 ThemeA CRUD 화면 통합 완료 | CRUD 미실행 | 미검증 |
|
||||
| UC5 | 해외업종·해외종목·해외지수 | 화면 통합 완료 | 해당 없음 | 미검증 |
|
||||
| UC6 | 전문가 조회·추천 preview·5행 항목 | 조회/선택 및 EList/추천 CRUD 화면 통합 완료 | CRUD 미실행 | 미검증 |
|
||||
| UC7 | 거래정지 검색·현재/120일 캔들 | 화면 통합 완료 | 해당 없음 | 미검증 |
|
||||
| GraphE | 4개 수동 재무 CRUD와 playlist 추가 | 화면 통합 완료 / 실환경 검증 대기 | 미실행 | 미검증 |
|
||||
| FSell | 개인·외국인·기관 수동 순매도 5행 | 화면 통합 완료 / 실환경 검증 대기 | 운영 데이터 write 미실행 | 미검증 |
|
||||
| VIList | 수동 VI 목록·순서·5개 단위 page | 화면 통합 완료 / 실환경 검증 대기 | 운영 데이터 write 미실행 | 수동 VI dataset 미검증 |
|
||||
| PList | 이름 있는 playlist 목록·저장·불러오기·삭제 | 화면 통합 완료 | 운영 DB write 미실행 | 복원 경로 미검증 |
|
||||
| AList | 프로그램 코드·이름 생성 | PList의 named playlist 화면에 통합 | 운영 DB write 미실행 | 해당 없음 |
|
||||
| ThemeA | KRX/NXT 테마 구성 CRUD | 화면 통합 완료 / 실환경 검증 대기 | 미실행 | 미검증 |
|
||||
| EList | 전문가 생성과 추천 구성 CRUD | 화면 통합 완료 / 실환경 검증 대기 | 미실행 | 미검증 |
|
||||
|
||||
## MainForm 매핑
|
||||
|
||||
원본 파일은 `MainForm.cs`와 `MainForm.Designer.cs`다.
|
||||
|
||||
| 원본 이벤트·컨트롤 | 원본 동작과 입력/저장 경계 | 새 구현 파일·bridge/workflow | 현재 상태 | 자동 테스트 근거 | DB-W / PGM |
|
||||
|---|---|---|---|---|---|
|
||||
| `Form1_Load`, `tabControl1_SelectedIndexChanged` | 실행 자산을 읽고 UC1~UC7을 탭에 배치하며 Tornado에 연결한다. | `MainWindow.xaml.cs`, `MainWindow.Playout.cs`, `Web/index.html`, `Web/app.js` | 화면 통합 완료 | `LegacyWebWorkflowIntegrationTests.cs`, `PlayoutBridgeProtocolTests.cs`, Web 전체 회귀 | DB-W 해당 없음 / PGM 일부 완료 |
|
||||
| `button9_Click`, `txtSearch_KeyPress`, `searchStock`, `jongmokCode` | 코스피·코스닥·NXT 두 시장씩 검색하고 이름, 코드, 시장을 선택한다. | `src/MBN_STOCK_WEBVIEW.Core/Data/StockSearch.cs`; native `search-stocks`; `Web/operator-workflow.js` | 화면 통합 완료 | `LegacyStockSearchServiceTests.cs`, `operator-workflow.test.cjs` | DB-W 없음 / `5001` 경로 일부 PGM 완료 |
|
||||
| `listView1_*`, `GridView1_*`, `SetPlayList`, `PlayList_DragDrop` | 실행 자산의 종목 컷을 선택·드래그해 enabled, 시장, 종목, 종류, 세부사항, page, 종목코드 행을 만든다. | `Web/operator-workflow.js`, `Web/app.js`의 종목 workflow와 표준 playlist entry | 화면 통합 완료 | `operator-workflow.test.cjs`, `candle-options-workflow.test.cjs` | DB-W 없음 / 전체 31개 PGM 미검증 |
|
||||
| `b1_Click` (`주요매출 구성`, `성장성 지표`, `매출액`, `영업이익`) | `GraphE` 네 모드를 연다. | `MainWindow.ManualFinancial.cs`, `Web/manual-financial-workflow.js`, `Web/manual-financial-ui.js` | 화면 통합 완료 / 실환경 검증 대기 | GraphE 표 참조 | DB-W 없음 / PGM 없음 |
|
||||
| `PlayList_CellClick`, `PlayList_KeyPress`, `checkBox1_CheckedChanged`, `btnup_Click`, `btndown_Click`, `btndelete_Click`, `btntdelete_Click` | 단일·Ctrl·Shift 선택, Space/전체 송출 체크, 순서 이동, 선택·전체 삭제. 송출 중 이동·전체 삭제를 막는다. | `Web/app.js`의 playlist 상태, snapshot lock, `Web/playout-safety.js` | 화면 통합 완료 | `playout-safety.test.cjs`, named/각 workflow의 trusted restore 테스트 | DB-W 없음 / PGM 제어 일부 완료 |
|
||||
| `button5_Click`, `btnload_Click` | `PList`를 열어 이름 있는 DB 플레이리스트를 저장·불러온다. | `MainWindow.NamedPlaylists.cs`, `src/MBN_STOCK_WEBVIEW.Core/Data/NamedPlaylistPersistence.cs`, `src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OracleNamedPlaylistMutationExecutor.cs`, `Web/named-playlist-workflow.js` | 화면 통합 완료 | named playlist Core/Infrastructure/Web/bridge 테스트 | DB-W 없음 / 복원 항목별 PGM 없음 |
|
||||
| `btnPrepare_Click`, `btnTake_Click`/F8, `btnNext_Click`, `btnTakeout_Click`/Esc | PREPARE, TAKE IN, 같은 장면 page NEXT 또는 다음 행 NEXT, StopAll 기반 TAKE OUT. | `MainWindow.Playout.cs`; `IPlayoutEngine`; native `playout-command`, `request-playlist-page-plans`; `Web/playout-safety.js` | 화면 통합 완료 | playout/Core/PageN/PGM sequence 테스트와 `playout-safety.test.cjs` | DB-W 해당 없음 / 승인된 `5001`, `5074` page 1·2 및 TAKE OUT만 PGM 확인 |
|
||||
| `btnback_Click`/F2, `ckback_CheckedChanged`/F3 | 허용 배경 파일 선택, 배경 없음 토글, 송출 중 변경 금지. | `MainWindow.Background.cs`; native `request-background-status`, `choose-background`, `toggle-background`; Web 배경 컨트롤 | 화면 통합 완료 | bridge·경로 검증과 앱 빌드 | DB-W 해당 없음 / 기능별 PGM 미검증 |
|
||||
| `timer1_Tick`, `timer2_Tick`, `timer3_Tick`, `MainForm_FormClosing`, `MainForm_Resize`, keyboard handlers | 자동 갱신, 상태 표시, 종료 정리, 단축키를 담당한다. | playout refresh scheduler, cancellation/lifetime hooks, Web 상태·단축키 | 화면 통합 완료 | refresh epoch/scheduler, playout safety, bridge 테스트 | DB-W 해당 없음 / 일부 PGM 완료 |
|
||||
|
||||
실제 PGM 완료는 이미 승인된 제한 회차의 `5001`과 `5074` 흐름만 뜻한다. 412개 전체나 아래 편집 화면의 실제 PGM 동등성을 뜻하지 않는다.
|
||||
|
||||
## UC1~UC7 매핑
|
||||
|
||||
### UC1 — 해외·환율·지수·업종·비교 action 트리
|
||||
|
||||
원본: `Control/UC1.cs`, `Control/UC1.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현 | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `UC1_Load`, `INI_parser` | 탭별 실행 자산을 읽어 category/leaf TreeView를 구성한다. | `legacy-fixed-workflow.js`, `industry-workflow.js`, `comparison-workflow.js`의 폐쇄형 inventory | 화면 통합 완료. 각 Web 테스트가 수량·중복·매핑을 고정한다. |
|
||||
| `chE_CheckedChanged`, `treeView_BeforeSelect`, `treeView_BeforeExpand/BeforeCollapse`, `treeView_DrawNode`, `treeView_MouseDown` | 전체 expand/collapse와 트리 표시를 제어한다. | Web category/section 렌더링과 펼침 상태 | 화면 통합 완료. 시각 상호작용이며 DB-W/PGM 대상 아님. |
|
||||
| `treeView_DoubleClick` | category 전체 또는 leaf를 playlist에 넣고 5·6·12개 PageN, NXT 제한, 업종 쌍, 비교 쌍을 계산한다. FSell·VI 수동 항목이면 전용 폼으로 분기한다. | 고정 328, 업종 44, 비교 9 workflow의 `create*PlaylistEntry`; page plan bridge; 수동 6개는 `manual-lists-workflow.js`와 `manual-lists-ui.js`로 분리 | 전체 화면 통합 완료. 실제 DB-W 없음, 전체 PGM 미검증. |
|
||||
| `treeView_AfterSelect`, `btnswap_Click` | 원본에서 실질 동작이 없거나 주석 처리된 이벤트다. | 별도 기능 없음 | 의도적으로 추가 동작을 만들지 않는다. |
|
||||
|
||||
### UC2 — 코스피·코스닥 업종 선택과 쌍
|
||||
|
||||
원본: `Control/UC2.cs`, `Control/UC2.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `UC2_Load` | 코스피/코스닥 업종 이름·코드를 DB에서 읽는다. | `src/MBN_STOCK_WEBVIEW.Core/Data/IndustrySelection.cs`; native `request-industries` | 화면 통합 완료. `LegacyIndustrySelectionServiceTests.cs`, `industry-workflow.test.cjs`. |
|
||||
| `listbox_DoubleClick`, `btnswap_Click` | 선택 업종을 두 슬롯에 회전 입력하고 순서를 바꾼다. | `Web/industry-workflow.js`의 selected/primary/secondary 입력 | 화면 통합 완료. 시장 혼합과 빈 슬롯을 fail closed 한다. |
|
||||
| UC1 업종 leaf 실행 | 단일, 2열, 수익률 5종, 캔들 12종, 시장 전체 3종으로 시장별 22개를 만든다. | `industry-workflow.js` | 44개 화면 통합 완료. 실제 DB-W 없음 / 업종별 PGM 없음. |
|
||||
|
||||
### UC3 — 비교 대상·저장 비교쌍
|
||||
|
||||
원본: `Control/UC3.cs`, `Control/UC3.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `UC3_Load`, `Data_Load` | 24개 고정 비교 대상을 읽고 로컬 `종목비교.dat`의 저장쌍을 불러온다. | `Web/comparison-workflow.js`; 24개 typed target; schema-versioned pair list | 화면 통합 완료. Web은 안전한 browser storage를 사용하며 raw 원본 파일을 신뢰하지 않는다. |
|
||||
| `btnsearch_Click`, `listBox_DoubleClick`, `listBox1_DoubleClick`, `btnsearch2_Click`, `FpSpread2_CellDoubleClick` | 국내 종목, 24개 시장 대상, 해외 종목을 두 슬롯에 회전 입력한다. | native `search-stocks`, `search-world-stocks`; comparison target normalizer | 화면 통합 완료. `comparison-workflow.test.cjs`가 회전·시장·해외 identity를 검증한다. |
|
||||
| `btnswap_Click`, `btnAdd_Click`, `btn1/2/3/4_Click`, `File_Save` | 쌍 교환, 추가, 선택/전체 삭제, 위/아래 이동 후 저장한다. | comparison pair append/delete/delete-all/reorder와 Web storage | 화면 통합 완료. 최대치·중복·손상 복원을 테스트한다. |
|
||||
| UC1 비교 leaf 실행 | 현재/예상 2열, 비교 캔들/라인, 5일·1/3/6/12개월 수익률의 9개 action | `comparison-workflow.js` | 9개 화면 통합 완료. 실제 DB-W 없음 / 비교 PGM 없음. |
|
||||
|
||||
### UC4 — 테마 검색·미리보기·송출 선택
|
||||
|
||||
원본: `Control/UC4.cs`, `Control/UC4.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `btn1_Click`, `GetThemeByKeyword` | KRX Oracle과 NXT 저장소에서 테마명·코드를 검색한다. | `src/MBN_STOCK_WEBVIEW.Core/Data/ThemeSelection.cs`; native `search-themes`; `Web/theme-workflow.js` | 검색 화면 통합 완료. `LegacyThemeSelectionServiceTests.cs`, `theme-workflow.test.cjs`. |
|
||||
| `FpSpread1_CellClick` | 선택 테마의 구성 종목과 입력 순서를 DB에서 읽고 중지 종목을 제외한다. | native `request-theme-preview`와 typed preview | 화면 통합 완료. 중복 key·시장 불일치·truncated preview를 거부한다. |
|
||||
| `btnnow_Click`, `btnpre_Click`, `btnnow_6_Click`, `btnnow_12_Click`, double-click | 5단 현재/예상, 6종목 현재, 12종목 현재를 입력순·상승률·하락률로 만들고 5/6/12 page 수를 계산한다. NXT 예상은 차단한다. | `theme-workflow.js`의 compatibility, page preview, playlist entry | 화면 통합 완료. 실제 DB-W 없음 / 테마 PGM 없음. |
|
||||
| `btn2_Click`, `btn3_Click`, `btn4_Click` | ThemeA 추가·편집 폼을 열거나 선택 테마와 구성 종목을 삭제한다. | `MainWindow.OperatorCatalogs.cs`, `Web/operator-catalog-workflow.js`, `Web/operator-catalog-ui.js` | ThemeA CRUD 화면 통합 완료. 실제 DB-W/PGM 없음. |
|
||||
|
||||
### UC5 — 해외업종·해외종목·해외지수
|
||||
|
||||
원본: `Control/UC5.cs`, `Control/UC5.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `UC5_Load` | 고정 해외지수 목록을 표시한다. | `Web/overseas-workflow.js`의 고정 지수 asset | 화면 통합 완료. |
|
||||
| `btnsearch1_Click`, `upjong_search` | 미국 해외업종의 입력명·표시명·symbol을 조회한다. | `src/MBN_STOCK_WEBVIEW.Core/Data/OverseasIndustryIndexSearch.cs`; native `search-overseas-industries` | 화면 통합 완료. `LegacyOverseasIndustryIndexSearchServiceTests.cs`. |
|
||||
| `btnsearch2_Click`, `jongmok_search` | US/TW 해외종목 이름·symbol을 조회한다. | `src/MBN_STOCK_WEBVIEW.Core/Data/WorldStockSearch.cs`; native `search-world-stocks` | 화면 통합 완료. `LegacyWorldStockSearchServiceTests.cs`. |
|
||||
| `btn1_Click`, `Account_Graph` | 업종/종목 현재 1열과 지수·종목 5/20/60/120/240일 캔들을 playlist에 넣는다. | `Web/overseas-workflow.js` | 화면 통합 완료. `overseas-workflow.test.cjs`; 실제 DB-W 없음 / 해외 PGM 없음. |
|
||||
|
||||
### UC6 — 전문가 목록·추천 종목·송출 선택
|
||||
|
||||
원본: `Control/UC6.cs`, `Control/UC6.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `UC6_Load`, `Data_Load`, `FpSpread1_CellClick` | `EXPERT_LIST`를 읽고 선택 전문가의 `RECOMMEND_LIST`를 PLAYINDEX 순서로 미리 본다. | `src/MBN_STOCK_WEBVIEW.Core/Data/ExpertSelection.cs`; native `search-experts`, `request-expert-preview`; `Web/expert-workflow.js` | 검색·선택 화면 통합 완료. `LegacyExpertSelectionServiceTests.cs`, `expert-workflow.test.cjs`. |
|
||||
| `btlistadd_Click` | 선택 전문가를 5행 page, 최대 20 page의 전문가 추천 항목으로 만든다. | `expert-workflow.js`의 native-normalized preview와 playlist entry | 화면 통합 완료. 실제 DB-W 없음 / 전문가 PGM 없음. |
|
||||
| `btnAdd_Click` | EList 신규 전문가 폼을 연다. | operator catalog expert create와 `operator-catalog-ui.js` | EList 신규 UI 통합 완료. |
|
||||
| `btnDelete_Click`, `btndel_Click`, `btnsave_Click`, 종목 검색·double-click | 전문가 삭제, 추천 종목 편집·삭제·재정렬·저장. 원본은 전문가/추천 행을 삭제 후 재삽입한다. | `MainWindow.OperatorCatalogs.cs`, `src/MBN_STOCK_WEBVIEW.Core/Data/ExpertCatalogPersistence.cs`, `src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OperatorCatalogMutationExecutor.cs`, `Web/operator-catalog-workflow.js`, `Web/operator-catalog-ui.js` | EList/전문가 CRUD 화면 통합 완료. 실제 DB-W/PGM 없음. |
|
||||
|
||||
### UC7 — 거래정지 종목
|
||||
|
||||
원본: `Control/UC7.cs`, `Control/UC7.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `btnsearch_Click`, `txts_KeyPress`, `search` | 거래정지 코스피와 코스닥 종목을 빈 검색 또는 부분 검색으로 합친다. | `src/MBN_STOCK_WEBVIEW.Core/Data/TradingHaltSelection.cs`; native `search-trading-halts`; `Web/trading-halt-workflow.js` | 화면 통합 완료. `LegacyTradingHaltSelectionServiceTests.cs`. |
|
||||
| `FpSpread1_CellClick` | 종목명 열 정렬 | Web 정규화 결과의 결정적 정렬 | 화면 통합 완료. |
|
||||
| `btn4_Click` (`현재가`, `120일 캔들`) | 시장·종목 identity로 현재 1열 또는 거래정지 120일 캔들 항목을 만든다. | `trading-halt-workflow.js` | 화면 통합 완료. `trading-halt-workflow.test.cjs`; 실제 DB-W 없음 / PGM 없음. |
|
||||
|
||||
## 전용 Form 매핑
|
||||
|
||||
### GraphE — 네 가지 수동 재무 편집기
|
||||
|
||||
원본: `Form/GraphE.cs`, `Form/GraphE.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `GraphE_Load`, `Data_Init`, `FpSpread1_CellClick`, `Data_Load` | 네 테이블 전체/검색 목록을 읽고 선택 행을 편집 DTO로 분해한다. | `src/MBN_STOCK_WEBVIEW.Core/Data/ManualFinancialScreens.cs`; native `request-manual-financial-list`, `request-manual-financial-load`; `Web/manual-financial-ui.js` | 화면 통합 완료 / 실환경 검증 대기 |
|
||||
| 종목 검색, `listBox_DoubleClick`, `upSearch_Click`, `downSearch_Click` | 정확한 종목을 선택하고 테이블 내 이름을 위/아래로 찾는다. | native stock master 재검증과 manual financial list/search | 화면 통합 완료. 이름만으로 시장·코드를 추정하지 않는다. |
|
||||
| `btadd_Click` | 기존 이름이면 update, 아니면 insert. `INPUT_PIE`, `INPUT_GROW`, `INPUT_SELL`, `INPUT_PROFIT`의 폐쇄형 필드를 저장한다. | native `create-manual-financial-record`, `update-manual-financial-record`; `src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OracleManualFinancialMutationExecutor.cs` | 화면 통합 완료. 단일 트랜잭션, optimistic `rowVersion`, no retry, OutcomeUnknown quarantine 구현. 실제 DB-W 없음. |
|
||||
| `btndel_Click`, `btnall_Click` | 선택 이름 삭제 또는 테이블 전체 삭제 확인 | native `delete-manual-financial-record`, `delete-all-manual-financial-records` | 화면 통합 완료. 실제 DB-W 없음. |
|
||||
| `btnAdd_Click`, row double-click, `Select_Item` | DB에 존재하는 행을 정확한 시장/종목과 결합해 1 page playlist 항목으로 추가한다. | native `request-manual-financial-selection`; `Web/manual-financial-workflow.js` | 화면 통합 완료. 저장 복원본은 fresh load + rowVersion/record 일치 + stock 재검증 + native selection 전까지 PREPARE 불가. PGM 없음. |
|
||||
|
||||
화면별 폐쇄형 매핑은 다음과 같다.
|
||||
|
||||
| 원본 모드 | 테이블 | 입력 | builder/code |
|
||||
|---|---|---|---|
|
||||
| 주요매출 구성 | `INPUT_PIE` | 종목, 기준일, 최대 5개 구성명·비율 | `s5076/5076` |
|
||||
| 성장성 지표 | `INPUT_GROW` | 매출·영업이익·순자산·순이익 증가율 각 4개와 분기 4개 | `s5079/5079` |
|
||||
| 매출액 | `INPUT_SELL` | 분기·금액 6쌍 | `s5080/5080` |
|
||||
| 영업이익 | `INPUT_PROFIT` | 분기·금액 6쌍 | `s5081/5081` |
|
||||
|
||||
자동 근거는 `LegacyManualFinancialScreenServiceTests.cs`, `OracleManualFinancialMutationExecutorTests.cs`, `manual-financial-workflow.test.cjs`, `manual-financial-bridge-integration.test.cjs`다.
|
||||
|
||||
### FSell — 수동 순매도 3종
|
||||
|
||||
원본: `Form/FSell.cs`, `Form/FSell.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `FSell_Load`, `data_load`, `ReadListFile` | 개인·외국인·기관별 로컬 파일에서 5행, 행마다 좌/우 종목·금액을 읽는다. | `src/MBN_STOCK_WEBVIEW.Infrastructure/Playout/S5025TrustedManualFileDataSource.cs`의 store/data source; native `request-manual-net-sell-data`; `Web/manual-lists-ui.js` | 화면 통합 완료 / 실환경 검증 대기 |
|
||||
| `btnok_Click`, `WriteListFile` | 정확히 5행을 저장하고 수동 순매도 항목 생성을 허용한다. | native `save-manual-net-sell-data`; `Web/manual-lists-workflow.js` | 화면 통합 완료. 검증된 versioned 데이터만 `s5025/5025`로 변환한다. 실제 파일 write는 자동 테스트 임시 디렉터리에서만 확인, 운영 데이터 write 없음. |
|
||||
| `btncn_Click` | 취소 시 placeholder 행을 유지하지 않는다. | workflow가 저장 성공·신뢰 데이터 없이는 항목을 만들지 않는다. | 화면 통합 완료. PGM 없음. |
|
||||
|
||||
자동 근거는 `TrustedManualSceneDataLoader5025Tests.cs`, `S5025TrustedManualFileDataSourceTests.cs`, `S5025TrustedManualFileStoreTests.cs`, `manual-lists-workflow.test.cjs`다.
|
||||
|
||||
### VIList — 수동 VI 목록
|
||||
|
||||
원본: `Form/VIList.cs`, `Form/VIList.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `VILIST_Load` | 로컬 VI 목록을 읽는다. | `src/MBN_STOCK_WEBVIEW.Infrastructure/Playout/ViTrustedManualFileStore.cs`; native `request-vi-manual-list`; `Web/manual-lists-ui.js` | 화면 통합 완료 / 실환경 검증 대기 |
|
||||
| 종목 검색, `listBox_DoubleClick` | 종목 master에서 코스피/코스닥 prefix와 종목명을 추가한다. | native `search-stocks`, `manual-lists-workflow.js`의 strict VI item | 화면 통합 완료. |
|
||||
| `btn1/2/3/4_Click` | 선택/전체 삭제와 위/아래 이동 | manual lists draft operations | 화면 통합 완료. |
|
||||
| `btnok_Click` | 목록을 저장하고 종목명을 comma로 결합해 항상 `5단 표그래프 / VI 발동(수동)`으로 추가하며 page를 5개 단위로 계산한다. | native `save-vi-manual-list`; trusted `s5074/5074`, 5개 단위 page entry | 화면 통합 완료. 자동 테스트는 `ViTrustedManualFileStoreTests.cs`, `manual-lists-workflow.test.cjs`, fixed workflow의 VI placeholder 테스트. 운영 write 없음. |
|
||||
| `btncancel_Click` | 저장·추가 없이 닫는다. | workflow 취소 시 mutation 없음 | 화면 통합 완료. 수동 VI dataset의 PGM 없음. 기존 generic `5074` PGM 검증을 VI 입력 검증으로 간주하지 않는다. |
|
||||
|
||||
### PList + AList — 이름 있는 DB 플레이리스트
|
||||
|
||||
원본: `Form/PList.cs`, `Form/AList.cs`와 각 Designer
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `PList_Load`, `Get_FileName_Folder` | `DC_LIST`의 프로그램 제목·코드를 조회한다. | native `request-named-playlist-list`; `named-playlist-workflow.js` | 화면 통합 완료 |
|
||||
| `AList_Load`, `GetNextCode`, `btnok_Click` | 다음 8자리 코드와 프로그램명을 생성해 `DC_LIST`에 추가한다. | native `create-named-playlist` | 화면 통합 완료. parameterized transaction 사용. |
|
||||
| `PList.data_save`, double-click/확인 | 기존 `PLAY_LIST`를 지운 뒤 enabled와 6개 표시 필드를 `LIST_TEXT` 및 ITEM_INDEX 순서로 저장한다. | native `replace-named-playlist`; trusted entry serialization | 화면 통합 완료. raw·untrusted entry는 저장 또는 PREPARE 불가. |
|
||||
| `PList.data_load`, double-click/확인 | 프로그램 코드별 `PLAY_LIST`를 ITEM_INDEX 순으로 읽어 playlist를 교체한다. | native `request-named-playlist-load`; resolver 기반 materialization | 화면 통합 완료. raw DB row는 builder/selection/page를 재검증할 때까지 PREPARE 불가. |
|
||||
| `PList.button1_Click` | 프로그램 정의 삭제 | native `delete-named-playlist` | 화면 통합 완료. 실제 운영 DB-W 없음. |
|
||||
| 취소 | 아무 변경 없이 닫는다. | mutation 요청 없음 | 화면 통합 완료. |
|
||||
|
||||
구현은 `src/MBN_STOCK_WEBVIEW.Core/Data/NamedPlaylistPersistence.cs`, `src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OracleNamedPlaylistMutationExecutor.cs`, `MainWindow.NamedPlaylists.cs`, `Web/named-playlist-workflow.js`에 있다. 자동 근거는 named playlist Core/Infrastructure/Web/bridge 테스트다. 실제 운영 DB write와 named playlist 전용 PGM 검증은 아직 없다.
|
||||
|
||||
### ThemeA — 테마 추가·편집
|
||||
|
||||
원본: `Form/ThemeA.cs`, `Form/ThemeA.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `Theme_Load` | KRX/NXT 선택, 기존 테마 구성 종목과 순서를 로드한다. | native `request-theme-catalog-list`, `request-operator-catalog-schema`; `operator-catalog-workflow.js`; `operator-catalog-ui.js` | 화면 통합 완료 / 실환경 검증 대기 |
|
||||
| `btnC_Click` | 시장별 테마명 중복을 확인한다. | native list/identity validation | 화면 통합 완료 |
|
||||
| 종목 검색·double-click | 같은 시장의 종목만 prefix가 포함된 구성 행으로 추가한다. | stock search + typed theme draft/preview | 화면 통합 완료 |
|
||||
| `btn1/2/3/4_Click`, Delete key | 선택/전체 삭제, 위/아래 이동 | operator catalog theme draft operations | 화면 통합 완료 |
|
||||
| `btnok_Click`, `GetNextCode` | 신규 코드를 만들거나 기존 `SB_LIST`/`SB_ITEM`을 교체하고 입력 순서를 저장한다. KRX와 NXT 저장소를 구분한다. | native `request-theme-catalog-next-code`, `create-theme-catalog`, `replace-theme-catalog`; atomic mutation executor | 화면 통합 완료. 실제 운영 DB-W/PGM 없음. |
|
||||
| UC4 테마 삭제 | `SB_ITEM` 후 `SB_LIST` 삭제 | native `delete-theme-catalog` | 화면 통합 완료. |
|
||||
|
||||
구현은 `src/MBN_STOCK_WEBVIEW.Core/Data/ThemeCatalogPersistence.cs`, `src/MBN_STOCK_WEBVIEW.Core/Data/OperatorCatalogSchemaValidation.cs`, `src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OperatorCatalogMutationExecutor.cs`, `MainWindow.OperatorCatalogs.cs`, `Web/operator-catalog-workflow.js`다. 자동 근거는 theme catalog, schema, executor, Web workflow 테스트다.
|
||||
|
||||
### EList — 전문가 신규 생성
|
||||
|
||||
원본: `Form/EList.cs`, `Form/EList.Designer.cs`
|
||||
|
||||
| 원본 이벤트·버튼 | 원본 입력·저장 경계 | 새 구현·bridge | 상태·검증 |
|
||||
|---|---|---|---|
|
||||
| `EList_Load`, `GetNextCode` | `EXPERT_LIST`의 다음 4자리 코드를 제안한다. | native `request-expert-catalog-next-code`; `operator-catalog-ui.js` | 화면 통합 완료 / 실환경 검증 대기 |
|
||||
| `btnok_Click` | 이름을 검증하고 `EXPERT_LIST`에 신규 전문가를 저장한다. | native `create-expert-catalog` | 화면 통합 완료. 실제 운영 DB-W 없음. |
|
||||
| UC6 저장·삭제 | 전문가와 `RECOMMEND_LIST` 구성 종목·금액·PLAYINDEX를 교체 또는 삭제한다. | native `replace-expert-catalog`, `delete-expert-catalog` | 화면 통합 완료. 실제 PGM 없음. |
|
||||
| `btncn_Click` | 변경 없이 닫는다. | mutation 요청 없음 | 화면 통합 완료. |
|
||||
|
||||
구현은 `src/MBN_STOCK_WEBVIEW.Core/Data/ExpertCatalogPersistence.cs`, 공통 schema/executor/native partial, `Web/operator-catalog-workflow.js`다. 자동 근거는 expert catalog, schema, executor, Web workflow 테스트다.
|
||||
|
||||
## bridge와 화면 로딩 상태 요약
|
||||
|
||||
| 기능군 | native request | workflow | 현재 `index.html`/`app.js` |
|
||||
|---|---|---|---|
|
||||
| 종목/고정/업종/비교/테마 조회/해외/전문가 조회/거래정지 | `search-stocks`, `request-industries`, `search-themes`, `request-theme-preview`, `search-world-stocks`, `search-overseas-industries`, `search-experts`, `request-expert-preview`, `search-trading-halts` | 각 전용 workflow | 로드·연결됨 |
|
||||
| 이름 있는 플레이리스트 | `request-named-playlist-list`, `request-named-playlist-load`, `create-named-playlist`, `replace-named-playlist`, `delete-named-playlist` | `named-playlist-workflow.js` | 로드·연결됨 |
|
||||
| GraphE | `request-manual-financial-list`, `request-manual-financial-load`, `request-manual-financial-selection`, `create-manual-financial-record`, `update-manual-financial-record`, `delete-manual-financial-record`, `delete-all-manual-financial-records` | `manual-financial-workflow.js`, `manual-financial-ui.js` | 로드·연결됨 |
|
||||
| FSell/VI | `request-manual-operator-data-status`, `request-manual-net-sell-data`, `save-manual-net-sell-data`, `request-vi-manual-list`, `save-vi-manual-list` | `manual-lists-workflow.js`, `manual-lists-ui.js` | 로드·연결됨 |
|
||||
| ThemeA/EList CRUD | `request-theme-catalog-list`, `request-expert-catalog-list`, `request-operator-catalog-schema`, theme/expert next-code, create/replace/delete requests | `operator-catalog-workflow.js`, `operator-catalog-ui.js` | 로드·연결됨 |
|
||||
|
||||
## 근거 파일 빠른 링크
|
||||
|
||||
| 영역 | 구현 | 자동 테스트 |
|
||||
|---|---|---|
|
||||
| 공통 화면·송출·배경 | [MainWindow](../MainWindow.xaml.cs), [Playout partial](../MainWindow.Playout.cs), [Background partial](../MainWindow.Background.cs), [Web app](../Web/app.js) | [playout safety](../tests/Web/playout-safety.test.cjs) |
|
||||
| 328 fixed / 44 industry / 31 stock / 9 comparison | [fixed workflow](../Web/legacy-fixed-workflow.js), [industry workflow](../Web/industry-workflow.js), [stock workflow](../Web/operator-workflow.js), [comparison workflow](../Web/comparison-workflow.js) | [fixed](../tests/Web/legacy-fixed-workflow.test.cjs), [industry](../tests/Web/industry-workflow.test.cjs), [stock](../tests/Web/operator-workflow.test.cjs), [comparison](../tests/Web/comparison-workflow.test.cjs) |
|
||||
| 테마 조회·해외·전문가 조회·거래정지 | [theme](../Web/theme-workflow.js), [overseas](../Web/overseas-workflow.js), [expert](../Web/expert-workflow.js), [trading halt](../Web/trading-halt-workflow.js) | [theme](../tests/Web/theme-workflow.test.cjs), [overseas](../tests/Web/overseas-workflow.test.cjs), [expert](../tests/Web/expert-workflow.test.cjs), [trading halt](../tests/Web/trading-halt-workflow.test.cjs) |
|
||||
| GraphE | [native partial](../MainWindow.ManualFinancial.cs), [Core service](../src/MBN_STOCK_WEBVIEW.Core/Data/ManualFinancialScreens.cs), [Oracle executor](../src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OracleManualFinancialMutationExecutor.cs), [workflow](../Web/manual-financial-workflow.js) | [Core](../tests/MBN_STOCK_WEBVIEW.Core.Tests/LegacyManualFinancialScreenServiceTests.cs), [Infrastructure](../tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/OracleManualFinancialMutationExecutorTests.cs), [Web](../tests/Web/manual-financial-workflow.test.cjs), [bridge](../tests/Web/manual-financial-bridge-integration.test.cjs) |
|
||||
| FSell / VI | [native partial](../MainWindow.ManualLists.cs), [FSell store/data source](../src/MBN_STOCK_WEBVIEW.Infrastructure/Playout/S5025TrustedManualFileDataSource.cs), [VI store](../src/MBN_STOCK_WEBVIEW.Infrastructure/Playout/ViTrustedManualFileStore.cs), [workflow](../Web/manual-lists-workflow.js) | [FSell store](../tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/S5025TrustedManualFileStoreTests.cs), [VI store](../tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/ViTrustedManualFileStoreTests.cs), [Web](../tests/Web/manual-lists-workflow.test.cjs) |
|
||||
| PList / AList | [native partial](../MainWindow.NamedPlaylists.cs), [Core service](../src/MBN_STOCK_WEBVIEW.Core/Data/NamedPlaylistPersistence.cs), [Oracle executor](../src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OracleNamedPlaylistMutationExecutor.cs), [workflow](../Web/named-playlist-workflow.js) | [Core integration](../tests/MBN_STOCK_WEBVIEW.Core.Tests/LegacyNamedPlaylistPersistenceIntegrationTests.cs), [Infrastructure](../tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/OracleNamedPlaylistMutationExecutorTests.cs), [Web](../tests/Web/named-playlist-workflow.test.cjs), [bridge](../tests/Web/named-playlist-bridge-integration.test.cjs) |
|
||||
| ThemeA / EList | [native partial](../MainWindow.OperatorCatalogs.cs), [theme persistence](../src/MBN_STOCK_WEBVIEW.Core/Data/ThemeCatalogPersistence.cs), [expert persistence](../src/MBN_STOCK_WEBVIEW.Core/Data/ExpertCatalogPersistence.cs), [executor](../src/MBN_STOCK_WEBVIEW.Infrastructure/Execution/OperatorCatalogMutationExecutor.cs), [workflow](../Web/operator-catalog-workflow.js) | [theme](../tests/MBN_STOCK_WEBVIEW.Core.Tests/LegacyThemeCatalogPersistenceServiceTests.cs), [expert](../tests/MBN_STOCK_WEBVIEW.Core.Tests/LegacyExpertCatalogPersistenceServiceTests.cs), [Infrastructure](../tests/MBN_STOCK_WEBVIEW.Infrastructure.Tests/OperatorCatalogMutationExecutorTests.cs), [Web](../tests/Web/operator-catalog-workflow.test.cjs) |
|
||||
|
||||
## 실제 검증 판정
|
||||
|
||||
| 항목 | 결과 |
|
||||
|---|---|
|
||||
| 자동 테스트 | Core 1,116개, Infrastructure 125개, Playout 374개가 Debug/Release x64에서 각각 통과했고 Web workflow·bridge 235/235도 통과했다. 412 action의 폐쇄형 매트릭스, 계약·경계·복원 실패와 native fail-closed gate를 검증한다. |
|
||||
| 실제 운영 DB write | **미실행.** GraphE, named playlist, ThemeA, EList의 mutation executor는 fake/계약 테스트로 검증했으며 운영 DB에는 쓰지 않았다. FSell/VI는 테스트용 격리 저장소만 사용했다. |
|
||||
| 실제 Tornado2 PGM | 제한된 승인 회차에서 `5001`, `5074` page 1·2, TAKE OUT을 확인했다. 이는 전체 412 action, GraphE, FSell, VI, ThemeA, EList, 이름 있는 playlist 각각의 UI 동등성 검증이 아니다. |
|
||||
| 남은 실환경 검증 | 다섯 전용 화면의 Web 연결과 새 signed `1.0.2.0` Release MSIX package-context 실행은 완료됐다. 실제 입력→운영 DB write→재조회와 각 전용 scene PGM 검증은 별도 승인·테스트 데이터·롤백 계획이 있는 회차에서만 수행한다. 운영 DB write 또는 새 Live TAKE IN을 승인 없이 실행하지 않는다. |
|
||||
72
docs/OPERATOR_WORKFLOW.md
Normal file
72
docs/OPERATOR_WORKFLOW.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 운영자 워크플로우 마이그레이션
|
||||
|
||||
## 결론
|
||||
|
||||
장면 엔진 35개와 운영 화면은 같은 범위가 아니다. 35개 builder가 DB DTO와 K3D mutation을 만들 수 있어도, 원본 운영자가 선택하던 종목·업종·비교 대상과 수동 입력을 Web UI가 만들지 못하면 실제 방송 업무는 시작할 수 없다.
|
||||
|
||||
이번 단계에서 캡처의 핵심 종목 흐름은 다음과 같이 복구했다.
|
||||
|
||||
`종목명 검색 → Oracle/MariaDB 결과 선택 → 종목용 컷 선택 → 플레이리스트 → F8 PREPARE/TAKE IN → NEXT/TAKE OUT`
|
||||
|
||||
## 복구된 종목 흐름
|
||||
|
||||
- KOSPI `T_STOCK`, KOSDAQ `T_KOSDAQ_STOCK`, NXT KOSPI `N_STOCK/N_ONLINE`, NXT KOSDAQ `N_KOSDAQ_STOCK/N_KOSDAQ_ONLINE`을 매개변수 쿼리로 검색한다.
|
||||
- LIKE의 `%`, `_`, `!`는 escape하고 검색어·결과 수·열 스키마·종목 코드 형식을 제한한다.
|
||||
- 검색 결과는 시장, 종목명, 종목 코드를 함께 보존하므로 원본처럼 이름을 다시 훑어 코드를 추정하지 않는다.
|
||||
- 실제 실행 자산 `bin/Debug/Res/종목.ini`의 31개 항목을 원본 순서로 표시한다.
|
||||
- 실행 자산 SHA-256은 `45DFB1804828F0E4A45F73D681AF0709CE5662872FAA49CFC9F7A0B940409E20`으로 고정했다. 소스 `RES/종목.ini`와 다른 `시간외단일가` 표기는 실행 자산을 기준으로 한다.
|
||||
- NXT 종목은 원본과 같이 `1열판기본_현재가`와 `N5001`만 허용한다.
|
||||
- 5일선·20일선은 컷 추가 시점의 사본이 아니라 현재 전역 체크 상태를 모든 캔들 항목에 동기화하고 PREPARE 직전에 다시 고정한다.
|
||||
- 저장된 typed 종목 항목은 builder, alias, selection, 종목, 이동평균선이 모두 재생성 결과와 같을 때만 복원한다. 실패한 항목은 일반 catalog 경로로 우회하지 못한다.
|
||||
- 플레이리스트 첫 열은 원본 의미와 같은 `송출` 여부다. 행 클릭은 삭제·이동 선택이며 Ctrl+클릭으로 복수 선택한다.
|
||||
- 현재 장면 행은 네이티브가 보낸 실제 page index/page count를 표시한다.
|
||||
- F8은 IDLE에서 PREPARE 성공을 받은 뒤 TAKE IN을 정확히 한 번 요청한다. Live/Test TAKE IN 승인이 잠겨 있으면 PREPARE도 자동 실행하지 않는다.
|
||||
- 원본 F2는 trusted scene-root 안의 배경 파일 선택을 열고, F3은 배경 없음 상태를 토글한다. PREPARE 단축키로 재사용하지 않는다.
|
||||
|
||||
## 현재 사용법
|
||||
|
||||
1. 대시보드, 코스피 또는 코스닥 메뉴에서 왼쪽 `종목 검색`에 종목명을 입력한다.
|
||||
2. 결과에서 정확한 종목과 시장을 선택한다.
|
||||
3. `종목용 컷`의 `+`를 누르거나 행을 더블클릭한다.
|
||||
4. 플레이리스트 첫 열의 `송출` 체크와 순서를 확인한다.
|
||||
5. DryRun에서 F8 또는 TAKE IN 버튼으로 PREPARE→TAKE IN을 검증한다.
|
||||
6. 실제 Test/Live에서는 회차별 안전 게이트가 TAKE IN을 허용한 경우에만 같은 버튼이 활성화된다.
|
||||
7. 종목 입력 영역의 `접기`를 누르면 전체 장면 catalog와 시장 데이터 영역을 사용할 수 있다.
|
||||
|
||||
## 실제 검증 결과
|
||||
|
||||
2026-07-11 로컬 운영 DB에서 다음을 확인했다.
|
||||
|
||||
- Oracle 21c 및 MariaDB health 정상
|
||||
- `삼성` 검색 63건: KOSPI 42, KOSDAQ 9, NXT KOSPI 12
|
||||
- `삼성전자`/`KR7005930003` 선택
|
||||
- `1열판기본_현재가` → builder `s5001`, alias `5001`, KOSPI/CURRENT selection 생성
|
||||
- 패키지 컨텍스트 DryRun의 PREPARE → TAKE IN, mutation preview 32개, TAKE OUT, 최종 편집 잠금 해제
|
||||
- COM 및 `KTAPConnect` 호출 없음
|
||||
|
||||
## 전체 운영 화면 구현 범위
|
||||
|
||||
35개 scene builder와 별개였던 원본 운영자 선택 표면을 모두 닫힌 workflow와 전용 화면으로 연결했다. 정확한 실행 action 분해는 다음과 같다.
|
||||
|
||||
| 범위 | 수량 | 상태 |
|
||||
|---|---:|---|
|
||||
| 해외·환율·지수 등 고정 action | 328 | 화면 통합 완료. 이 중 수동 placeholder 6개는 FSell/VIList 화면으로만 연다. |
|
||||
| 코스피·코스닥 업종 action | 44 | 화면 통합 완료 |
|
||||
| 종목 action | 31 | 화면 통합 완료 |
|
||||
| 비교 action | 9 | 화면 통합 완료 |
|
||||
| 합계 | **412** | 명령 생성·strict restore 자동 매트릭스 완료 |
|
||||
| UC3 고정 비교 선택지 | 24 | 비교 화면의 typed target으로 통합 완료 |
|
||||
|
||||
추가 전용 화면도 연결됐다.
|
||||
|
||||
- GraphE: 주요매출 구성, 성장성 지표, 매출액, 영업이익의 조회·편집·삭제·playlist 추가
|
||||
- FSell/VIList: trusted local store의 저장·재조회·버전 검증 뒤 `s5025`/`s5074` 추가
|
||||
- ThemeA/EList: 테마·전문가와 구성 종목의 생성·교체·삭제
|
||||
- PList/AList: Oracle `DC_LIST`/`PLAY_LIST` 이름 있는 저장·불러오기·삭제
|
||||
- F2/F3: trusted 배경 선택과 배경 없음 토글
|
||||
|
||||
수동 입력 DB 쓰기와 이름 있는 플레이리스트 저장은 read-only query executor와 분리된 매개변수 repository/transaction 경계를 사용한다. 송출이 IDLE임을 네이티브 engine과 workflow 양쪽에서 확인할 수 없거나, browser 상관관계·commit 결과가 불명확하면 모든 operator write를 프로세스 수명 동안 차단하고 자동 재시도하지 않는다.
|
||||
|
||||
## 완료 판정
|
||||
|
||||
412개 실행 명령, UC3 비교 선택지, 수동 입력, 배경, 이름 있는 저장·불러오기까지 Web 화면 연결과 자동 계약 검증은 완료됐다. 다만 실제 운영 DB write와 각 경로의 Tornado2 PGM 확인은 UI 구현 완료와 별도다. 승인된 테스트 데이터·롤백 계획·회차별 PGM 승인이 없는 실환경 mutation이나 TAKE IN은 완료 증거를 만들기 위해 임의로 실행하지 않는다.
|
||||
@@ -7,9 +7,9 @@
|
||||
| 항목 | 상태 |
|
||||
|---|---|
|
||||
| 기본 모드 | `DryRun`; COM 객체와 `KTAPConnect`를 만들지 않음 |
|
||||
| 자동 테스트 | 최종 전체 재검증에서 Core Debug/Release x64 각각 790/790, Playout 각각 374/374, Infrastructure 각각 65/65(합계 각 1,229/1,229), Web safety 12/12 통과; 이후 테스트 추가 시 개수보다 실패 0건을 기준으로 재확인 |
|
||||
| Visual Studio 2026 | Debug/Release x64 빌드 성공 |
|
||||
| trusted Release x64 MSIX | 생성·서명 검증·x64 설치·package context 실행 성공. 실제 DB DryRun에서 5001 timer refresh, 5074 playlist NEXT와 page 1→2 Page NEXT, TAKE OUT 정리를 확인; 나머지 PageN/마지막 경계는 자동 테스트로 검증 |
|
||||
| 자동 테스트 | 최종 전체 재검증에서 Core Debug/Release x64 각각 1,116/1,116, Playout 각각 374/374, Infrastructure 각각 125/125(합계 각 1,615/1,615), Web 235/235 통과; 실패·skip·경고 0건 |
|
||||
| Visual Studio 2026 | MSBuild `18.7.8.30822` Debug x64와 signed Release x64 패키지 빌드 성공 |
|
||||
| trusted Release x64 MSIX | `1.0.2.0` 생성·서명 검증·x64 설치·package context 실행 성공. SHA-256 `4A4ED867D16B75C1C82CB55DA5111E0502573F486B8B897889069843D9DF5072`; source Web 24개 일치, 금지 자산 0건, 기본 DryRun과 전체 UI·실제 DB 검색·오류 이벤트 0건 확인. Round H의 실제 DB DryRun/Live workflow 증거는 아래에 별도 보존 |
|
||||
| 실제 데이터 전체 scene smoke | 34개 도달 가능 builder 통과: 33개 DB + `s5025` trusted 외부 CP949 파일. `s8086` diagnostic 포함 Oracle/MariaDB query 55건 통과 |
|
||||
| `s5025` trusted 수동 파일 | 외부 CP949 source 통합 검증 통과; 실제 파일/환경은 계속 Git 밖에서 회차별 preflight |
|
||||
| `s5006` `Video\큐브배경.vrv` | 현재 승인 Cuts root에서 누락 |
|
||||
@@ -263,6 +263,8 @@ vendor monitor의 실제 명령 표기는 버전에 따라 다를 수 있으므
|
||||
|
||||
`OutcomeUnknown`은 단순 실패 code가 아니라 실제 출력 결과를 모른다는 latch다. Cancelled, Rejected, `WEB_TIMEOUT` 또는 UI 오류로 낮추지 않는다. timeout quarantine은 native process-lifetime latch이므로 WebView reload나 오류 창으로 해제되지 않는다. refresh fault marker는 성공한 TAKE OUT 뒤 native reset에만 맞춰 제거할 수 있지만 unknown/quarantine latch에는 영향을 주지 않는다. process를 재시작해 표시를 지우는 행위도 실제 출력 복구가 아니다.
|
||||
|
||||
GraphE, ThemeA/EList, FSell/VIList 또는 이름 있는 플레이리스트 쓰기에서 commit·파일 교체 결과나 browser 응답 상관관계를 확인하지 못한 경우에도 동일한 원칙을 적용한다. 어느 한 subsystem에서 `OutcomeUnknown`이 발생하면 네이티브 global operator-mutation quarantine이 모든 operator write를 프로세스 수명 동안 차단한다. 다른 편집 화면으로 옮겨 쓰거나 같은 값을 다시 저장하지 않는다. 앱을 종료한 뒤 Oracle `INPUT_*`/`SB_*`/`EXPERT_*`/`DC_LIST`/`PLAY_LIST` 또는 trusted local file을 읽기 전용으로 대조하고, 실제 결과를 확정·복구한 다음 새 앱 프로세스와 새 명시적 작업으로 시작한다. 송출 engine/workflow가 없거나 IDLE을 양쪽에서 증명하지 못하는 상태, PREPARED/PROGRAM, callback pending, refresh, shutdown 중에도 모든 operator mutation은 fail closed다.
|
||||
|
||||
## Rollback과 unload
|
||||
|
||||
### 명확히 출력 전 실패한 경우
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 35개 Scene 동등성 완료 매트릭스
|
||||
|
||||
기준 시각은 2026-07-11이다. 원본 `C:\Users\MD\source\repos\MBN_STOCK_N`은 읽기 전용으로만 분석했으며, 이 문서 작업에서도 원본 파일을 수정하지 않았다. 원본 35개 builder의 파일 해시는 [`legacy-scene-source-hashes.json`](legacy-scene-source-hashes.json), 원본 구조 기준선 검사는 [`Test-LegacySceneBaseline.ps1`](../scripts/Test-LegacySceneBaseline.ps1)에 있다.
|
||||
기준 시각은 2026-07-12이다. 원본 `C:\Users\MD\source\repos\MBN_STOCK_N`은 읽기 전용으로만 분석했으며, 이 문서 작업에서도 원본 파일을 수정하지 않았다. 원본 35개 builder의 파일 해시는 [`legacy-scene-source-hashes.json`](legacy-scene-source-hashes.json), 원본 구조 기준선 검사는 [`Test-LegacySceneBaseline.ps1`](../scripts/Test-LegacySceneBaseline.ps1)에 있다.
|
||||
|
||||
이 문서에서 **구현 완료**는 DTO → mutation builder, 실제 데이터 loader, playlist selection resolver 또는 명시적 runtime route, 자동 테스트가 모두 존재한다는 뜻이다. **자동 동등성 완료**는 원본 35개 builder의 source hash/inventory 기준선을 고정하고, 원본 구현에서 도출한 오브젝트·mutation·호출 순서·45개 alias·PageN 기대값을 새 구현의 매트릭스와 자동 suite로 검증했다는 뜻이다. 실행 중인 구 구현과 새 구현을 같은 입력으로 직접 호출해 의미를 대조하는 comparator가 있다는 뜻은 아니다. **실제 Tornado 검증**은 승인된 scene과 회차에만 적용한다. 현재 마이그레이션 기준선은 완료됐지만 실제 PGM 증거를 승인되지 않은 나머지 scene으로 확대 해석하지 않는다.
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
| 원본 inventory와 hash 기준선 | 완료 | 35/35 builder, 원본 기준선 스크립트 35/35 |
|
||||
| DTO와 mutation builder | 완료 | registry가 정확히 35개 builder를 발견하고 catalog와 1:1 대조 |
|
||||
| loader와 runtime route | 완료 | MainForm 도달 가능 builder 34개, active alias 45개를 fail-closed route로 등록; `s8086`은 원본과 같이 무alias 진단 전용 |
|
||||
| 자동 테스트 | 완료 | 소스 `fa0eae7b61f57f134dfd30ebf1e59e9cc2cccfc5`: Core 790/790, Playout 374/374, Infrastructure 65/65가 Debug/Release x64에서 각각 통과했고 Web safety 12/12, 원본 baseline 35/35도 통과 |
|
||||
| Visual Studio 2026 빌드 | 완료 | MSBuild `18.7.8`로 Debug/Release x64 및 앱 패키지 빌드 성공 |
|
||||
| Release x64 MSIX | 완료 | 서명·설치·내용 감사와 package-context 실행 통과. SHA-256 `D51E8CB637860D9F0377AEE6FF691D7D954BA0FF7E30B1AB65443DA153BC5429`; packaged `DryRun`에서 `5001 PREPARE → fresh TAKE IN → 자동 refresh 1회 → 5074 playlist NEXT → Page NEXT → TAKE OUT`을 확인하고 전체 PageN 경계는 자동 테스트로 확인 |
|
||||
| 자동 테스트 | 완료 | Core 1,116/1,116, Playout 374/374, Infrastructure 125/125가 Debug/Release x64에서 각각 통과했다. 구성별 1,615개, 전체 3,230개이며 실패·skip·경고는 0건이다. Web 235/235와 원본 baseline 35/35도 통과 |
|
||||
| Visual Studio 2026 빌드 | 완료 | MSBuild `18.7.8.30822`로 Debug x64와 signed Release x64 앱 패키지 빌드 성공 |
|
||||
| Release x64 MSIX | 완료 | `1.0.2.0` 서명·설치·내용 감사와 package-context 실행 통과. SHA-256 `4A4ED867D16B75C1C82CB55DA5111E0502573F486B8B897889069843D9DF5072`; Web 24개가 source와 일치하고 금지 자산은 0건이며 기본 `DryRun`에서 전체 UI와 실제 DB 종목 검색을 확인. Round H의 승인된 실제 송출 증거는 아래 별도 행과 운영 문서에 보존 |
|
||||
| 실제 데이터 전체 장면 smoke | 완료 | 34개 도달 가능 builder 전체 통과: 33개 Oracle/MariaDB loader와 `s5025` trusted 외부 CP949 파일. 무alias `s8086` diagnostic도 통과했고 실제 Oracle/MariaDB query 55/55가 성공했다. |
|
||||
| 이번 마이그레이션의 실제 Tornado2/PGM | **승인 범위 완료** | 계획 SHA-256 `55C7755C2F874B4B012239117D4AB717BBCE194E7DCC8DA9B0E40D094FF8CA19`의 `MBNWEB-20260711-H`에서 `5001 → 자동 refresh 1회 → 5074 page 1 → page 2 → TAKE OUT`을 PGM과 Network Monitoring으로 함께 확인. 최종 검은 화면, retry 0, `OutcomeUnknown = false` |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user