Files
MBN_STOCK_WEBVIEW/docs/OPERATOR_UI_PARITY.md

22 KiB

운영자 UI 동등성 인벤토리

문서 성격: 이 문서는 역사·상세 증거를 보존한다. 현행 완료·차단 판정은 MIGRATION_STATUS.md가 우선한다. 아래의 “미실행”, “대기”, “별도 승인” 표현과 과거 테스트 수치는 해당 시점의 기록이며 현재 상태가 아니다.

기준일: 2026-07-15

제품과 판정 기준

현재 이관 앱은 웹사이트가 아니라 .NET 8 / C# / WinUI 3 / WebView2 Windows 데스크톱 프로그램인 MBN_STOCK_WEBVIEW.LegacyParityApp이다. WebView2는 패키지 안의 로컬 HTML/CSS/JavaScript를 표시한다.

Web은 원본 UI를 표현하고 사용자 intent를 전달한다. 원본 이벤트의 상태 전이, DB identity, playlist, PageN과 송출 상태는 LegacyOperatorController의 C# snapshot이 권위다. Web 메시지는 LegacyBridgeProtocol의 strict JSON allowlist에 없는 필드·값·명령을 거부한다.

이 문서의 판정은 다음을 구분한다.

판정 의미
UI/이벤트 이관 원본 컨트롤과 클릭 이벤트가 실제 LegacyParityApp 화면 → strict bridge → C# workflow로 연결됨
자동 동등성 원본 inventory·DTO·mutation·호출 순서·경계값을 자동 테스트로 비교함
개발 DB 통합 실제 개발 Oracle/MariaDB에서 create/readback/delete/absence를 확인함
개발 PGM 통합 개발 Tornado2 Network Monitoring과 PGM 화면을 함께 확인함
외부자산 필요 코드 경로는 있으나 Git/MSIX 밖의 실제 영상·배경이 제공되지 않음

원본 보존

  • 원본 C:\Users\MD\source\repos\MBN_STOCK_N은 읽기 전용으로만 분석했다.
  • 원본 Cuts도 읽기 전용 검증에만 사용하며 수정·복사하지 않는다.
  • 비밀번호, 라이선스, 벤더 DLL, 인증서, 실제 컷·영상·배경과 로컬 설정은 Git에 넣지 않는다.

원본 Designer 이벤트 전수 감사

원본 *.Designer.cs가 실제로 구독하는 이벤트를 전수 조사한 결과는 186개 Designer 구독, 화면별 중복을 합친 171개 고유 핸들러다. 선언만 있고 Designer에서 구독하지 않는 메서드는 수에 넣지 않았다. 171개는 IMPL 131, DEAD 20, VISUAL 10, DRAG 9, SAFETY 1로 모두 분류했다. 같은 이름의 핸들러라도 화면이 다르면 별도 바인딩으로 센다.

상세 원본 파일·구독 줄·분류 근거는 LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md에 있다.

원본 실행 action inventory

동적 테마·전문가 DB 행과 전용 편집기의 데이터 행은 아래 고정 수량에 중복해 더하지 않는다.

집합 원본 UI 수량 현재 경계 상태
fixed action MainForm 해외·환율·지수와 UC1 328 LegacyFixedActionCatalog + strict action/section intent 이관
업종 action UC1 + UC2 44 LegacyIndustryActionCatalog + C# section batch 이관
종목 컷 MainForm 좌측 검색·컷 31 LegacyStockCutCatalog 이관
비교 action UC1 + UC3 9 24개 target + LegacyComparisonWorkflowController 이관
업무 탭 MainForm TabControl 10 identity 기반 활성화·순서 변경 이관

328개 fixed action 중 수동 전제 6개는 임의 DTO로 만들지 않는다. 개인·외국인·기관 순매도 3개는 FSell의 신뢰된 5행 입력으로, 5단·6종목·12종목 트리의 VI placeholder 3개는 원본 VIList가 만든 s5074/5074 5개 단위 PageN으로만 활성화한다.

화면 단위 현황

원본 화면 이관된 핵심 동작 현재 구현 개발 DB/파일 검증 개발 PGM/자산 경계
MainForm 종목 검색, 31컷, playlist, 배경, 송출, 단축키, 종료 확인 LegacyParityApp shell + C# controller 실제 DB 검색/read smoke PASS 송출 최종 결과는 검증 문서에 기록
UC1 328 fixed, 업종·비교 트리, 부모/leaf batch C# 폐쇄 inventory와 원자적 section materialize read-only selector 검증 장면별 PGM은 별도
UC2 업종 검색, 두 슬롯 회전·교환, 44 action industry workflow/controller Oracle read PASS 장면별 PGM은 별도
UC3 비교 대상·검색·쌍 CRUD·9 action comparison workflow/controller 원본 8쌍 1회 import·재시작 영속성 검증 장면별 PGM은 별도
UC4 KRX/NXT 테마 검색·preview·5/6/12 선택 theme workflow; 목록 행 단일 클릭 KRX/NXT selector PASS 외부 scene 자산과 PGM 별도
UC5 해외업종·해외종목·해외지수 overseas workflow/controller Oracle selector PASS s6001 영상 13개 외부자산 미제공
UC6 전문가 검색·추천 preview·5행 선택 expert workflow; 목록 행 단일 클릭 selector PASS 장면별 PGM은 별도
UC7 거래정지 검색·현재/120일 캔들 trading-halt workflow; 원본 단일 클릭 Oracle selector PASS 장면별 PGM은 별도
GraphE 4개 재무 CRUD, 정렬·찾기, 행 더블클릭 playlist 추가 LegacyManualFinancialWorkflow 개발 DB 4개 테이블 write PASS 전용 scene PGM 별도
FSell 개인·외국인·기관 각 5행, 확인 시 저장+추가+닫기 LegacyManualListsWorkflow + trusted store 원본 형식 read와 격리 write 검증 s5025 trusted 파일 전제
VIList 종목 추가·삭제·이동, 5개 단위 page, 확인 시 저장+추가+닫기 LegacyManualListsWorkflow + trusted store 원본 형식 read와 격리 write 검증 s5074 전용 입력 PGM 별도
PList 목록, 행 더블클릭 load/save, 확인, 삭제 LegacyNamedPlaylistWorkflow 개발 DB create/save/read/delete/absence PASS 복원 항목별 scene PGM 별도
AList 다음 코드와 프로그램명 신규 생성 named playlist workflow에 통합 위 named playlist 시나리오로 PASS 해당 없음
ThemeA KRX/NXT 테마 생성·편집·삭제, 이름 중복확인, 종목 구성·순서 LegacyOperatorCatalogWorkflow + exact-title 조회 개발 DB KRX/NXT 각 1개 PASS scene PGM 별도
EList 전문가 생성·편집·삭제, 추천 종목·금액·드래그 순서 LegacyOperatorCatalogWorkflow + opaque row reorder 개발 DB expert 1개 PASS scene PGM 별도

UC4/UC6의 결과 행은 고정 action 트리의 click handler에 버블링하지 않는다. UC4 테마, UC6 전문가와 UC7 거래정지는 원본처럼 단일 클릭으로 선택/playlist 동작을 수행하고, fixed/industry/comparison 트리의 원본 double-click과 독립적으로 처리한다.

MainForm 이벤트 매핑

원본 이벤트 원본 의미 LegacyParityApp 동작
Form1_Load 자산·DB·탭·Tornado 초기화 WebView local UI와 C# composition root 초기화; 기본 DryRun
tabControl1_SelectedIndexChanged 탭별 최초 데이터 조회 10개 identity별 C# activation gate; 최초 진입 1회 load, 재진입 snapshot 유지
탭 drag 이벤트 10개 탭 표시 순서 교환 dragover 대상 진입 시 identity와 예상 위치를 C#이 검증해 교환; 중복 전달은 no-op, active tab·playlist 불변
검색 버튼/Enter 종목 검색 원본 KOSPI→KOSDAQ→NXT 순서와 마지막 이름 일치 규칙 유지
컷 click/double-click/key/drag 원본 런타임 컷 선택·추가 최대 50 물리행, pointer double-click, Arrow/Home/End/Space와 Ctrl/Shift selection mark, batch 추가
playlist click/key/buttons/drag F8 후보, 삭제 선택, enabled, 이동, 삭제, 단일 행 drag F8 후보·PROGRAM·DEL 집합·Shift anchor를 분리하고 drag는 실제 source 한 행만 이동; 송출 mutation 차단 유지
F2/F3 배경 선택·없음 trusted sibling background root만 허용; 누락·reparse·escape fail closed
F8 선택 후보 TAKE IN IDLE/PREPARED/PROGRAM에서 그 시점의 후보를 새 PREPARE → TAKE IN으로 실행; PROGRAM·후보·DEL 집합·Shift anchor는 독립
NEXT Page NEXT 또는 다음 행 같은 scene PageN 여부를 C#이 판정
Escape TAKE OUT modal이 없을 때만 StopAll 기반 TAKE OUT intent
FormClosing 종료 확인 기본 취소 확인창; 자동 TAKE OUT/반대 명령 없음

FarPoint 대체와 클릭 규칙

FarPoint UI는 Web table/list로 표현한다. 다음 의미는 원본과 같이 유지한다.

  • plain/Ctrl/Shift/Ctrl+Shift 선택과 현재 행
  • 첫 행은 자동 F8 후보지만 실제 클릭 전에는 DEL 선택이 아니며, F8/Home/End도 기존 DEL 집합과 Shift anchor를 덮어쓰지 않음
  • column header 정렬과 현재 표시 순서
  • 위/아래 이동, 선택/전체 삭제와 enabled 토글
  • playlist의 실제 drag source 한 행을 이동하는 임의 before/after drop; 비연속 Ctrl/Shift 집합은 삭제 선택으로만 사용
  • UC6/EList 추천 행의 opaque rowId 기반 drag 재정렬
  • single-click과 double-click을 컨트롤별로 구분
  • 부모 section 전체 추가는 모든 자식을 먼저 materialize한 뒤 한 번에 commit
  • 수동/지원 불가 child가 있으면 부분 추가 없이 전체 차단
  • modal이 열리면 F2/F3/F8/Escape, Delete/Space/Home/End 등 전역 동작 격리
  • stale generation, 예상하지 않은 row id, 추가 payload field를 strict bridge에서 거부

GraphE 행 double-click은 fresh DB record를 다시 확인한 뒤 한 행을 추가하고 닫는다. Theme 결과 double-click은 원본의 5행 현재가 경로를 사용한다. PList 행 double-click은 현재 save/load 모드에 맞춰 동작하며, 이름만으로 DB identity를 추정하지 않는다.

drag 이관 경계

원본 동작 Web 입력 C# 권위와 중복 안전
FarPoint AllowRowMove 내부 custom MIME와 opaque source/target rowId, before/after 실제로 끌어 잡은 source 한 행만 이동한다. 수동 Ctrl/Shift 삭제 선택을 다중 행 drag로 확대하지 않으며, 체크박스에서 시작한 drag와 PREPARED/PROGRAM/pending/unknown 변경을 거부한다.
tab_DragOver/MouseDown/Move/Up drop을 기다리지 않고 dragover로 hover-swap-tabs 전송 C# 탭 identity와 expectedSourceIndex/expectedTargetIndex가 현재 순서와 일치할 때만 교환하므로 같은 메시지의 중복 전달이 순서를 되돌리지 않는다.
ListView.MouseDown/MouseMove pointer capture와 Windows SM_CXDRAG/SM_CYDRAG 비대칭 rectangle Chromium native drag 임계값을 쓰지 않는다. DPI-aware API의 96-DPI 값을 host DIP로 전달하고 XamlRoot.RasterizationScale/devicePixelRatio 비율로 retained browser zoom까지 보정한다. Windows 설정·화면·DPI 변경 및 state 게시 때 갱신하며, left/top 포함·right/bottom 제외 경계를 넘은 뒤 playlist 안에서 놓을 때만 현재 C# 선택 집합을 physical order로 한 번 추가한다.
PList DataSource/click/double-click non-empty 목록 첫 행 자동 선택, 행 click 즉시 선택, double-click save/load 열기·새로고침·추가·삭제 뒤 첫 행을 선택한다. 다른 행 click은 exact requestId 영수증 전까지 확인·삭제를 잠그고 동일 opaque ID의 double-click만 선택 완료 뒤 실행해 이전 행 DB mutation을 차단한다.
UC6 FpSpread2.AllowDragDrop ThemeA/EList 편집행의 내부 custom MIME와 opaque rowId 워크플로가 임의 before/after 위치를 계산한다. 존재하지 않는 ID, 같은 행, 추가 payload 필드는 strict bridge에서 거부하거나 no-op 처리한다.

실제 마우스 검증에서는 playlist 행 drop이 조상 drop zone으로 버블링해 현재 선택된 컷을 한 번 더 추가하는 문제가 드러났다. 조상은 이제 exact legacy-selected-cuts text/plain token만 처리하고 playlist row custom MIME와 외부 text는 무시한다. 따라서 한 row drop에서 reorder와 cut append가 함께 발생하지 않는다.

체크박스 origin도 브라우저 동작을 반영해 보강했다. Chromium의 dragstart.target은 실제 pointer가 체크박스에서 시작했어도 draggable 조상 행일 수 있다. pointerdown 때 checkbox origin row를 기억해 이어지는 dragstart를 거부하고 pointerup/pointercancel/dragend에서 지운다. 회귀 테스트는 이 target 형태, 단일 source 행 이동, row MIME의 조상 무시, 외부 text 거부와 exact selected-cut token의 1회 처리를 DOM event 순서로 재현한다.

ThemeA 이름 중복확인

원본 ThemeA의 중복확인 버튼을 operator-catalog-name-check로 이관했다. Web은 이름만 check-operator-catalog-theme-name intent로 전송하고 KRX/NXT, 코드와 테이블 identity는 C# workflow가 소유한다. 선택된 provider의 SB_LIST에 exact title parameterized COUNT(*) 조회를 한 번 수행하며 DB mutation은 실행하지 않는다. 중복, 사용 가능, 결과 불명 상태를 구분하고, 조회 결과를 확정할 수 없으면 쓰기 없이 fail closed한다. 원본처럼 편집 중 자기 행을 제외하지 않으므로 이름을 바꾸지 않은 행은 중복으로 판정된다.

원클릭 TAKE IN과 숨김 PREPARE

원본 운영 화면의 핵심 동작은 별도 PREPARE를 먼저 누르는 것이 아니라 F8/TAKE IN 한 번으로 송출하는 것이다. 현재 보이는 TAKE IN은 idle에서도 활성 조건을 만족하면 다음을 실행한다.

  1. playlist selection과 page를 C# snapshot으로 고정
  2. DB/신뢰 파일 DTO와 PageN을 fresh load
  3. 장면 mutation과 transaction 순서를 적용해 Prepare 정확히 1회
  4. 성공한 prepared scene에 TakeIn 정확히 1회

엔지니어링용 native PREPARE control과 explicit workflow는 테스트를 위해 유지하지만 Web UI에서 hidden이다. TAKE IN 실패·timeout·OutcomeUnknown이면 자동 재시도하지 않으며 성공한 prepared ownership을 추측해 지우지 않는다.

Visual Studio Development Live 시작 경계

공유 MBN_STOCK_WEBVIEW.slnLaunch와 패키지 시작 프로필은 MBN_STOCK_WEBVIEW.LegacyParityApp을 명시적인 시작 프로젝트로 사용한다. 저장소의 기본값은 계속 DryRun이고 이 Development Live 부트스트랩은 Release에서 적용되지 않는다. Development Live는 정확한 --development-live 인자, Debug 빌드, %LOCALAPPDATA% 아래 Git 제외 승인 파일의 세 조건을 모두 만족한 프로세스에서만 구성된다.

승인 파일은 정확한 다섯 속성, 최대 4096바이트, canonical JSON, exact authorization 문자열과 독립 검수된 native/Interop SHA-256 두 개를 요구한다. 알 수 없는 속성, 중복 속성, reparse 경로, I/O 오류 또는 일부 환경 설정 실패는 모두 fail closed한다. Live authorization은 process scope에서 마지막에 설정되고 MainWindow/engine 생성 시 한 번 캡처된다. 이 경로는 기존 trustedLiveOutputEnabled, scene allowlist, asset 검사와 명령 안전 게이트를 완화하지 않는다. 상세 절차는 DEVELOPMENT_LIVE_VISUAL_STUDIO.md에 있다.

2026-07-15 실제 UI·package·연결 검증

설치한 signed Release x64 MSIX는 15,213,188 bytes, SHA-256 357E17426C45FF516592EE0177D0F95502A98AF084759348ABC191BA5ED21FD5다. 설치와 package-context 실행을 확인했다. Release에 --development-live를 전달한 회차는 Debug-only gate 때문에 DryRun으로 남았고 Tornado TCP 연결과 Network Monitoring 변경이 없었다.

실제 WebView 마우스/CDP 입력의 확인 범위는 다음과 같다.

  • 삼성 검색 결과 63개, 삼성출판사 선택, 선택한 컷 3개를 한 번의 drop으로 playlist 3행에 추가
  • 당시 package의 playlist multi-row block reorder와 enabled 체크박스 origin drag 차단. block reorder는 이후 원본 재감사에서 source 단일 행 이동으로 교정됐으므로 현재 코드의 단일 행 drag package 실측으로 간주하지 않음
  • mouse release 전에 dragover로 시장 탭 순서 교환
  • EList 추천행 5개 drag reorder. 수량 입력칸에서 시작한 실제 마우스 drag는 순서를 바꾸지 않고, 행의 비입력 영역에서 시작한 drag만 순서를 바꾸는 것을 확인
  • ThemeA 결과 500건과 exact-title 중복확인 read 성공

별도 승인된 Development Live 회차의 장비 로컬 시간(KST) 14:28:28에 HELLO request와 success를 각 1회, 14:43:10에 BYE 1회를 확인했다. scene, PREPARE, TAKE 계열, DB write는 모두 0건이다. 최종 Network Monitoring 원문은 300,007자, SHA-256 45858322F60C135858002EB6243D0474F51F1965E23D2332D397C3A3B5DB8049다. 이 회차는 Live 연결/해제 경로만 검증하며 scene/PGM 방송 송출 성공을 뜻하지 않는다.

PageN과 NEXT

scene page size 규칙
s5074 5 테마/전문가/VI 등 5행 경로
s5077 6 6종목 테마 경로
s5088 12 12종목 테마 경로

행을 만들 때 pageCount = min(20, ceil(itemCount / pageSize))를 사용하고, 송출을 시작할 때 operator row의 current/total suffix를 해당 on-air cycle 동안 고정한다. column 3이 정확히 5단 표그래프, 6종목 현재가, 12종목 현재가인 행만 Page NEXT를 허용한다. 0행, 정확한 경계, 마지막 부분 페이지, 20페이지 cap, 21페이지 요청 거부, retained on-air scene Page NEXT와 다음 enabled playlist 항목 NEXT를 자동 테스트로 비교한다.

개발 DB write 증적

실제 개발 Oracle/MariaDB에서 production executor를 사용한 9개 충돌 격리 시나리오가 create/save → fresh readback → delete → absence를 통과했다.

기능 시나리오
GraphE INPUT_PIE/GROW/SELL/PROFIT 4
PList/AList named playlist 2
ThemeA KRX/NXT 2
EList expert 1
합계 9

이는 개발 DB 통합 증거이며 운영 DB write를 수행했다는 뜻이 아니다. write 재시도는 없고, 결과가 불명확하면 cleanup과 다음 시나리오도 실행하지 않는 fail-closed 규칙을 유지한다.

read-only·scene·asset 증적

  • 실제 Oracle/MariaDB 필수 scene selector 33/33, 전체 query 58건 PASS
  • 원본 scene builder 자동 기준선 35/35
  • MainForm 도달 runtime 34개 builder와 active alias 45개
  • 승인된 Cuts에 45 alias 대응 .t2s 존재
  • s5006 Video\큐브배경.vrv 1개와 s6001 국가 영상 13개는 외부자산 미제공
  • sibling 배경\기본.vrv도 외부자산 미제공

마지막 14개 영상과 기본.vrv의 부재는 UI/scene 코드 실패가 아니다. 해당 기능은 자산이 제공될 때까지 COM 전에 차단하며 임의 파일로 대체하지 않는다.

구현·테스트 빠른 링크

영역 현재 실행 구현 주요 테스트/근거
WinUI 3 + WebView2 shell MainWindow.xaml.cs, Web app, Web layout thin client
C# 업무 권위 LegacyOperatorController.cs LegacyApplication tests
strict bridge LegacyBridgeProtocol.cs LegacyBridge tests
송출 MainWindow.Playout.cs, playout-ui.js, LegacyPlayoutWorkflow.cs LegacyPlayoutWorkflowTests.cs
수동 목록 MainWindow.ManualLists.cs, LegacyManualListsWorkflow.cs manual-list tests
GraphE LegacyManualFinancialWorkflow.cs manual-financial tests
PList/AList LegacyNamedPlaylistWorkflow.cs named-playlist tests
ThemeA/EList LegacyOperatorCatalogWorkflow.cs catalog tests
Designer 이벤트 감사 LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md 186 subscriptions / 171 unique handlers
VS Development Live DEVELOPMENT_LIVE_VISUAL_STUDIO.md strict local authorization와 Debug-only bootstrap
scene matrix SCENE_EQUIVALENCE.md 35/35 builder, 45 alias, PageN matrix
2026-07-15 증적 LEGACY_PARITY_VALIDATION_20260715.md signed Release, 실제 UI와 제한된 Live 연결 범위

현재 signed Release MSIX의 hash·크기·설치·DryRun 실행과 위 실제 마우스/CDP UI 범위는 확인했다. 최종 회귀는 .NET Debug/Release x64에서 각각 2,446/2,446, Web Node에서 438/438, Visual Studio 2026 Debug/Release x64 빌드에서 경고 0·오류 0이다. 다만 HELLO/BYE만 수행한 Live 회차를 scene PREPARE/TAKE/PGM 성공으로 확대하지 않는다.