Files
MBN_STOCK_WEBVIEW/docs/DEVELOPMENT_LIVE_HANDOFF.md

17 KiB

개발 PGM 인수 PC 실제 송출 확인 절차

적용 범위

이 절차는 상사 또는 인수 담당자의 PC가 방송에 연결되지 않은 지정 개발 장비이고, 그 장비의 로컬 Tornado2 PGM이 개발 검증 대상임을 확인한 경우에만 사용한다. 창 제목이 PGM인 것만으로 개발 장비임이 증명되지는 않는다. 실제 방송 PROGRAM일 가능성이 있거나 라우팅을 확인할 수 없으면 시작하지 말고 운영·비지정 환경 승인 게이트를 적용한다.

이 절차가 여는 Live 경로는 Debug|x64MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package) 한 프로세스에만 유효하다. Release와 일반 설치본의 기본 모드는 계속 DryRun이다. Release를 Live로 바꾸거나 사용자·시스템 환경 변수에 Live 승인을 영구 저장하지 않는다.

인수 전에 별도로 전달할 항목

다음 항목은 저장소가 아니라 승인된 사내 전달 경로로 제공한다.

  • New-LegacyRuntimeBundle.ps1로 생성한 runtime bundle ZIP과 별도 신뢰 경로로 전달할 기대 SHA-256.
  • DB endpoint와 계정 정보. 메신저 화면, 작업 기록 또는 Git에 값을 남기지 않는다.
  • Tornado2/K3D x64 벤더 설치본과 해당 장비용 라이선스 설치 절차.
  • 벤더 배포본 또는 관리자 검수로 독립 승인된 native DLL과 Interop DLL의 SHA-256 두 개.
  • 개발 PGM의 실제 Network Server TCP port, 창 제목, 출력 라우팅과 담당자 확인 정보.

현재 설치된 DLL의 해시를 그 자리에서 계산한 뒤 같은 값을 승인값으로 삼지 않는다. 라이선스 파일, DLL, 인증서 또는 자산을 앱 폴더에 임의 복사해 등록·라이선스 검사를 우회하지 않는다.

1. 개발 장비와 대상 고정

담당자 두 사람이 다음 내용을 먼저 확인한다.

  1. 이 PC와 로컬 Tornado2/PGM은 개발용이며 실제 방송 라우팅에 영향이 없다.
  2. Tornado2* 프로세스는 정확히 하나이고 주 창 제목은 승인값과 정확히 일치한다.
  3. Tornado2의 Tools > Option > Control > Network Server > TCP Port에 표시된 값을 직접 읽는다. 문서나 예제의 30001을 추정값으로 사용하지 않는다.
  4. 해당 TCP LISTEN 소유 PID와 Tornado2 PID가 같고, 실행 도중 프로세스 세대가 바뀌지 않는다.
  5. View > Network Monitoring Window와 PGM 화면을 동시에 관찰할 담당자가 있다.

한 항목이라도 불명확하면 이후 명령을 보내지 않는다.

2. 검증된 Git 밖 runtime bundle 설치

원본 runtime tree를 새 PC에 직접 복사하거나 수동으로 ZIP을 만들지 않는다. 원본을 보유한 지정 개발 장비에서 읽기 전용 bin\Debug을 입력으로 다음 스크립트를 실행한다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\New-LegacyRuntimeBundle.ps1 `
  -LegacyRuntimeSourceRoot '<read-only-MBN_STOCK_N-bin-Debug>' `
  -OutputDirectory '<new-empty-bundle-output-directory>'

-OutputDirectory를 생략하면 Git 제외 artifacts\legacy-runtime-bundles\<UTC>-<GUID> 아래에 새 출력 디렉터리를 만든다. 결과물은 다음 세 파일이다.

LegacyRuntimeBundle.zip
LegacyRuntimeBundle.manifest.json
LegacyRuntimeBundle.zip.sha256

생성기는 전체 Cuts tree와 프로젝트가 허용한 비민감 Res 파일 34개만 폐쇄형으로 묶는다. MmoneyCoder.ini와 그 복사본·백업, DB 파일, 자격증명, vendor DLL, 라이선스, 인증서, 실행 파일과 임의 archive는 거부한다. 따라서 MmoneyCoder.ini는 Debug를 포함한 어떤 빌드 입력·출력이나 runtime bundle에도 필요하지 않으며 넣어서는 안 된다.

ZIP은 승인된 사내 전달 경로로 보내고, LegacyRuntimeBundle.zip의 기대 SHA-256은 ZIP 또는 동봉 .sha256 파일과 다른 신뢰 경로로 인수자에게 전달한다. 같은 폴더의 해시 파일만 보고 ZIP을 신뢰하지 않는다.

새 PC의 저장소 루트에서 ZIP을 직접 풀지 말고 다음 초기화 스크립트를 사용한다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-LegacyRuntimeBundle.ps1 `
  -ZipPath '<received-LegacyRuntimeBundle.zip>' `
  -ExpectedSha256 '<separately-approved-64-hex-zip-sha256>'

저장소 루트가 현재 디렉터리가 아니면 검토한 절대 경로를 -RepositoryRoot로 추가한다. 초기화기는 압축을 풀기 전에 별도로 전달받은 ZIP SHA-256을 확인하고, manifest와 각 파일의 경로·길이·SHA-256, reparse/root 이탈과 금지 파일 부재를 검사한다. 성공한 bundle은 기본적으로 다음 Git 밖 경로에 설치한다.

%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\RuntimeBundles\<ZIP-SHA256>

그 뒤 저장소 루트의 Git 제외 Directory.Build.local.props를 만들어 LegacyRuntimeAssetsMode=Required와 검증된 설치 root를 고정한다. 이 파일을 손으로 만들거나 경로를 환경 변수로 임시 주입하지 않는다. ZIP, 설치 root와 Directory.Build.local.props도 Git에 추가하지 않는다.

초기화기가 출력한 설치 root의 Cuts를 대상으로 coverage를 확인한다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Test-LegacyCutCoverage.ps1 `
  -CutRoot '<initialized-runtime-root>\Cuts'

현재 authoritative 자산에도 다음 영상 14개는 없다.

  • s5006: Video\큐브배경.vrv 1개
  • s6001: Video\20201008_<국가>.vrv 13개

coverage가 이 14개를 누락으로 보고하는 동안 관련 action은 PREPARE하지 않는다. 다른 scene, built-in asset, 빈 파일, root 이탈 또는 reparse 항목이 하나라도 발견되면 인수를 중단한다. 이 스크립트는 자산이 하나라도 없으면 의도적으로 실패 종료하므로, 결과가 정확히 알려진 14개 영상 누락뿐인 경우에도 전체 coverage Passed로 기록하지 않고 영향 없는 scene만 제한적으로 인수한다. 누락 영상을 비슷한 파일로 대체하지 않는다.

초기화 뒤에는 별도 MSBuild 경로 인자나 환경 변수 없이 다음 빌드가 성공하는지 확인한다.

dotnet build .\src\MBN_STOCK_WEBVIEW.LegacyParityApp\MBN_STOCK_WEBVIEW.LegacyParityApp.csproj `
  -c Debug `
  -p:Platform=x64

앱이 소스 전용 모드라고 표시되거나 bin\SourceOnly에서 시작되면 Development Live를 진행하지 않는다. bundle 초기화 결과와 Directory.Build.local.props를 고친 뒤 전체 자산 빌드부터 다시 확인한다.

3. DB 로컬 설정

Debug/Release와 Package 앱의 DB 설정은 모두 실행 사용자 전용 경로에 만든다.

%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\database.local.json

저장소 루트에서 기존 초기화 스크립트를 사용한다. Oracle이 service name을 쓰는 환경이면 -OracleSid 대신 -OracleServiceName을 사용한다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-DatabaseConfig.ps1 `
  -OracleHost '<approved-host>' `
  -OraclePort <approved-port> `
  -OracleSid '<approved-sid>' `
  -OracleUserName '<approved-user>' `
  -MariaDbHost '<approved-host>' `
  -MariaDbPort <approved-port> `
  -MariaDbDatabase '<approved-database>' `
  -MariaDbUserName '<approved-user>'

비밀번호는 스크립트의 보안 프롬프트에만 입력한다. 생성 파일은 현재 Windows 사용자만 읽고 수정할 수 있어야 한다. 개발 DB가 아니라 운영 DB를 가리키거나 endpoint가 불명확하면 송출 검증으로 넘어가지 않는다. DB 연결 확인은 DB 운영 가이드의 read-only smoke만 먼저 수행하고, 실패 시 Tornado 명령을 보내지 않는다.

4. K3D 설치, 라이선스와 승인 해시 확인

벤더 절차로 Tornado2/K3D x64와 장비 라이선스를 먼저 설치한다. 저장소의 점검은 레지스트리와 파일을 읽을 뿐 COM을 활성화하지 않는다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Inspect-K3DRegistration.ps1

Registry64, TypeLib/CLSID 양방향 매핑, Apartment, AMD64 PE, HKCU override 부재 검사가 모두 성공해야 한다. 점검 성공은 라이선스 성공을 대신하지 않으므로 벤더 방식으로 라이선스도 별도 확인한다. native와 Interop의 실제 파일은 각각 독립 승인된 SHA-256과 일치해야 하며 둘 중 하나라도 다르면 중단한다.

5. 보호된 로컬 송출 설정

저장소 루트에서 다음 스크립트를 실행해 두 파일을 함께 만든다. port는 이번에 Tornado2 화면에서 직접 확인한 값이고, 두 해시는 독립 승인값이어야 한다. 기존 승인 프로필이 별도 출력 채널을 사용할 때만 검증된 숫자를 -OutputChannel로 추가하며, 기본 player를 쓰는 경우에는 생략한다.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-DevelopmentLiveConfig.ps1 `
  -PlayoutHost 127.0.0.1 `
  -PlayoutPort <verified-network-server-tcp-port> `
  -NativeSha256 '<independently-approved-64-hex-native-sha256>' `
  -InteropSha256 '<independently-approved-64-hex-interop-sha256>'

스크립트는 %LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config 아래의 일반 파일 두 개를 원자적으로 생성하고 현재 Windows 사용자 전용 ACL을 적용한다. LocalAppData 상위 경로에 reparse point가 있거나 기존 파일이 있으면 중단한다. 기존 파일을 덮어쓸 때는 내용을 별도로 검토하고 대상이 정확한 경우에만 -Force를 명시한다. -Force 갱신은 기존 Live 승인 파일을 먼저 무효화하므로 두 파일 중 하나라도 쓰기에 실패하면 송출 승인이 남지 않는다. 경로·endpoint·해시를 Git이나 실행 로그에 복사하지 않는다.

playout.local.json

초기화 스크립트가 만든 파일을 읽기 전용으로 검토해 다음 계약과 일치하는지 확인한다. Config/playout.example.json은 비밀값 없는 구조 참고용일 뿐 수동 복사본으로 사용하지 않는다.

항목 인수 값
mode 항상 DryRun. Development Live 프로세스만 일시적으로 Live로 덮어쓴다.
host 로컬 PGM이면 숫자형 loopback 127.0.0.1. localhost 또는 원격 주소를 추정하지 않는다.
port Tornado2 화면에서 이번에 직접 확인한 Network Server TCP port
tcpMode / clientPort 1 / 0
sceneDirectory null. 검증된 bundle이 빌드 출력에 배치한 기본 Cuts를 사용한다.
outputChannel 승인된 개발 PGM 라우팅 값. 기존 승인 프로필이 기본 player를 쓰는 경우에만 null
testSceneAllowlist 아래 active alias 45개만 허용
trustedLiveOutputEnabled true
reconnectEnabled / maximumReconnectAttempts 인수 회차에서는 false / 0
maximumAutomaticRefreshesPerTakeIn 최초 인수 회차에서는 0
5001, 5006, 5011, 5016, 50160, 5023, 5024, 5025, 5026, 5029,
5032, 5037, 5068, 5070, 5072, 5074, 5076, 5077, 5078, 5079,
5080, 5081, 5082, 5083, 5084, 5085, 5086, 50860, 5087, 5088,
6001, 6067, 8001, 8002, 8003, 8018, 8032, 8035, 8040, 8046,
8051, 8056, 8061, 8067, N5001

8010, 8086, 임의 파일명과 절대 scene 파일 경로는 allowlist에 추가하지 않는다. 실제 endpoint, 채널, 경로와 allowlist가 든 이 파일을 Git이나 지원 첨부파일에 넣지 않는다.

playout.development-live.local.json

경로는 다음과 같다.

%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\playout.development-live.local.json

파일에는 정확히 다음 다섯 속성만 둔다.

{
  "schemaVersion": 1,
  "mode": "Live",
  "authorization": "I_AUTHORIZE_LIVE_PROGRAM_OUTPUT_FOR_THIS_LAUNCH",
  "nativeSha256": "<independently-approved-64-hex-native-sha256>",
  "interopSha256": "<independently-approved-64-hex-interop-sha256>"
}

주석, trailing comma, 중복·추가 속성을 넣지 않는다. 두 해시와 승인 근거는 Git 밖에 보관한다. 현재 설치 파일에서 즉석 계산한 값으로 placeholder를 채우지 않는다. 자세한 strict 파일 규칙은 Visual Studio Development Live 설정을 따른다.

6. 정확한 로컬 PGM 연결 전용 확인

Network Monitoring을 먼저 연다. 독립 승인 해시는 이 진단을 실행할 현재 PowerShell 프로세스에만 설정한 뒤 실제 port로 connect-only 진단을 한 번 실행한다.

$env:MBN_STOCK_K3D_NATIVE_SHA256 = '<independently-approved-native-sha256>'
$env:MBN_STOCK_K3D_INTEROP_SHA256 = '<independently-approved-interop-sha256>'

dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
  -c Debug -p:Platform=x64 -- `
  --pgm-connect-diagnostic `
  --i-understand-this-will-contact-current-pgm-tornado-via-ktap-connect-and-disconnect-only `
  --host 127.0.0.1 `
  --port <verified-network-server-tcp-port> `
  --expected-pgm-window-title PGM

이 진단은 KTAP Connect → Disconnect만 수행하고 render API를 노출하지 않지만 PGM 제어 세션에는 접촉한다. 성공 결과의 completed: true, outcomeUnknown: false, renderCommandSurfaceExposed: false, renderCommandAttempted: false와 같은 시각의 Network Monitoring HELLO 성공을 사람이 함께 확인한다.

timeout, OutcomeUnknown, 대상 PID·시작 시각·listener 변경 또는 결과 불일치가 생기면 같은 진단을 반복하지 않는다. 새 명령을 보내지 말고 PGM과 Network Monitoring 상태를 읽기 전용으로 확인한 뒤 새 인수 회차를 계획한다.

7. Development Live 최소 인수 시퀀스

  1. 기존 앱 인스턴스를 정상 종료한다.
  2. Visual Studio에서 구성 Debug, 플랫폼 x64, 시작 대상 Legacy Parity App (VS F5)를 선택한다.
  3. 실행 프로필을 MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)로 선택하고 F5로 시작한다.
  4. 앱이 소스 전용 또는 DryRun으로 시작했다면 실제 명령을 시도하지 않는다. runtime bundle, 시작 인자와 두 로컬 파일을 고친 뒤 앱을 새로 시작한다.
  5. 최초 인수는 자산이 완전한 사전 합의 scene 하나만 사용한다. 기본 최소 회차는 active alias 5001CONNECT 1회 → PREPARE 1회 → 화면·Network Monitoring 확인 → TAKE IN 1회 → 화면 확인 → TAKE OUT 1회 → DISCONNECT 1회다.
  6. PREPARE 성공과 PGM 상태를 확인하기 전에는 TAKE IN을 누르지 않는다. NEXT, Page NEXT, timer refresh, 다른 scene은 최초 최소 회차에 추가하지 않는다.
  7. TAKE OUT과 DISCONNECT 결과가 명확히 성공한 뒤 앱을 정상 종료한다.

각 단계에서 앱 결과, lifecycle callback, PGM 화면과 Network Monitoring 기록이 서로 맞아야 한다. timeout, OutcomeUnknown, callback 누락, 화면 불일치, 대상 identity 변경 또는 license/hash/ allowlist 실패가 발생하면 다음 동작, 같은 동작 반복, 반대 동작이나 추측성 cleanup을 하지 않는다. PGM/Tornado2를 강제 종료하지 말고 상태를 보존한다.

8. DryRun 복귀와 인수 완료 조건

Live 앱을 종료하면 부트스트랩이 만든 Live 환경은 프로세스와 함께 사라져야 한다. playout.local.jsonmode는 계속 DryRun이어야 한다. 다음으로 MBN_STOCK_WEBVIEW.LegacyParityApp - Explicit DryRun (Package) 프로필을 실행해 실제 KTAP 통신 없이 UI가 시작되는지 확인한다. Release 검증도 이 DryRun 프로필로만 수행하며 --development-live를 Release Live 수단으로 사용하지 않는다.

다음 항목이 모두 맞아야 인수를 완료한다.

  • 지정 개발 PC와 정확한 로컬 PGM 대상 확인
  • 외부 runtime bundle과 허용 scene 검증
  • K3D x64 등록, 장비 라이선스와 두 독립 승인 해시 확인
  • 개발 DB read-only smoke 성공
  • %LOCALAPPDATA% 설정 파일의 내용·ACL 검증
  • connect-only 진단과 최소 5001 회차가 retry 0, OutcomeUnknown=false로 종료
  • 최종 TAKE OUT/IDLE, DISCONNECT와 Explicit DryRun 재시작 확인
  • 누락 영상 14개 관련 action이 제한 상태임을 인수자에게 고지

실제 endpoint, 자격증명, 해시, 자산 경로, 화면 캡처와 Network Monitoring 증거는 승인된 Git 밖 인수 기록에만 보관한다.

Git에 넣지 않는 항목

  • Cuts, .t2s, image, texture, .vrv 영상과 방송 자산
  • LegacyRuntimeBundle.zip, manifest·해시 파일, 설치된 RuntimeBundlesDirectory.Build.local.props
  • Res\MmoneyCoder.ini, database.local.json과 DB 자격증명
  • playout.local.json, playout.development-live.local.json, runtime-folders.local.json
  • Tornado/K3D native DLL, Interop DLL, 라이선스 파일·키
  • native/Interop 승인 해시와 승인 근거
  • MSIX 서명 인증서, 개인 키와 암호
  • 실제 host, port, output channel, PGM 정보
  • 실제 출력 캡처, Network Monitoring 화면과 민감 로그

Debug Package 빌드가 로컬 실행을 위해 승인 runtime 자산을 stage하더라도 그 출력, AppPackages 또는 설치 파일을 소스 저장소나 일반 첨부파일로 올리지 않는다. 고객 배포본으로 재사용하지도 않는다. Git에는 소스, 비밀값 없는 예제와 이 절차만 유지한다.