[자격증명] 접속 문자열 우선순위를 환경변수 > appsettings.Development.json > appsettings.json > ServerInfo ini 로 세웠다. 병원 설치본은 설정 없이 [000]bin 의 MSYSTECH_ServerInfo.ini 를 자동으로 찾아 붙는다(레거시와 동일한 MD5 → 3DES-ECB 복호). - ServerInfoReader 를 [200]SheetMe 에서 복사 이식(vendoring — 두 저장소가 분리돼 있어 ProjectReference 불가, 레거시 암복호 규약은 변할 이유가 없는 고정 자산). 헤더에 동기화 의무 명시. - 실측 검증: ini 566라인/병원 엔트리 76개, CurrentServer=029.BSGH 복호 후 실제 접속 성공. - SaveMode 기본값을 File 로 되돌렸다. ini 의 CurrentServer 가 운영 병원 DB 를 가리키므로 DB 쓰기는 명시적으로 켠 단말에서만 활성화되어야 한다. - ConfigService 로 단일 소유화 — ConfigLoader.Load() 11회 호출이 ini 파싱 + 3DES 복호를 매번 반복하던 것을 1회로. 죽어 있던 Designer:GridSize/SnapThreshold 를 SnapEngine 에 배선하고, 쓰이지 않던 His:Provider 와 DefaultPaperWidth/Height 는 제거했다(후자는 설정이 아니라 레거시 패리티 상수다). [산출물] 8.6MB/34파일 → 7.2MB/26파일. - EmrDataContext 제거 — M.Framework.DBAccess/TableFramework/M.MW.Data.EMR 의 유일한 소비처였는데 그 클래스가 어디서도 인스턴스화되지 않았다. DB 접근은 전부 raw Oracle 클라이언트를 쓴다. - Microsoft.Web.WebView2 는 ExcludeAssets="runtime" — M.Framework.WPF 전이 의존일 뿐 소스 참조 0건. [000]bin 과의 이름 충돌 3건도 함께 사라진다. - Production.pubxml(win-x64, FDD, SatelliteResourceLanguages=ko). RID 를 csproj 가 아니라 pubxml 에 둔 이유는 csproj 에 넣으면 dotnet build/test 까지 RID 별 복원을 타기 때문이다. - tools/publish.ps1 — 비밀값 하드 게이트 + [000]bin 충돌 경고 + SHA256 매니페스트 + zip. 게이트는 역방향으로 검증했다(appsettings.json 에 실접속 정보를 넣고 실행 → 정상 차단). - nuget.config 신설 — 사내 피드가 개발자 개인 OneDrive 경로라 다른 머신에서 복원이 불가능했다. %MSYS_NUGET_FEED% 환경변수로 받게 해 최소한 실패 원인이 드러나게 했다. [배포 규약] docs/DEPLOYMENT.md. [000]bin 최상위 평면 복사를 금지한다 — 실측 결과 Oracle.ManagedDataAccess.dll 이 겹치고 (신규 .NET Core 5,434KB ↔ 기존 .NET FW 4,602KB), 덮으면 그 폴더의 레거시 EXE 187개가 전부 Oracle 접속 불능이 된다. [000]bin\SheetMe\ 하위 폴더에 둔다 — Information/Log/ OCR서식생성기/SpreadDesign 등 기존 앱들과 같은 방식이다. FDD 로 배포한다: [000]bin\OCR서식생성기 가 이미 net10.0 + WindowsDesktop.App 10.0.0 을 요구하며 운영 중이라 런타임 존재가 확인된다. 없는 단말이 나오면 -SelfContained 한 번이면 된다. [로깅] AppLog — LogManager 배선. 모든 호출을 try/catch 로 감싸 로깅 실패가 업무를 막지 않게 했다. - Redact 필수 — 접속 문자열을 값으로 들고 다니므로 예외 메시지에 자격증명이 섞일 수 있다. 기록 직전 1회 통과시킨다. - LogLevel 은 열거형이 아니라 문자열 속성이라 오타를 컴파일러가 못 잡고, 잘못된 값이면 FIXED 만 남고 나머지가 조용히 사라진다. LogType 열거값의 이름으로만 지정하게 했다. - 문서에 있는 HandleShutdown 은 6.0.0 DLL 에 실제로는 없어(XML 문서가 앞서 있음) 쓰지 않는다. 대신 기록이 비동기 배치라 스모크에서 짧게 폴링해 확인한다. - 로그 경로는 실행 폴더\logs\Designer, 쓰기 불가 시 %LocalAppData% 폴백(쓰기 프로브까지 확인). [전역 예외] Dispatcher/AppDomain/TaskScheduler 3종을 진단 분기보다 앞에 등록했다. UI 예외는 기록 후 계속 진행한다(편집 중 문서를 예외 하나로 잃지 않게) — 단 10초 내 5회면 무한 팝업 루프이므로 강제 종료한다. DialogService.ShowError 도입 — 우리가 던진 안내성 예외는 메시지를 그대로 보여주고, 그 외는 일반화 문구 + 오류 코드만 노출한다(코드가 로그 줄머리와 같아 전화 한 통으로 특정된다). ex.ToString() 전문을 그대로 띄우던 2곳을 정리했다. 로그인/권한거부/DB저장은 감사 이벤트(FIXED)로 남긴다. 검증: 테스트 70/70, edit-smoke 실패 0(마스킹 5건 + 로그 배선 1건 추가), 왕복 1,271건 diff 0/예외 0, db-save-smoke 제자리 갱신 통과. publish.ps1 정방향/역방향 모두 확인. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.0 KiB
SheetMe 배포 가이드
요약
pwsh tools/publish.ps1
산출물을 각 병원의 [000]bin\SheetMe\ 하위 폴더에 푼다. 접속 정보는 코드나 설정에 넣지 않는다 — [000]bin\MSYSTECH_ServerInfo.ini에서 자동으로 읽는다.
🔴 [000]bin 최상위에 평면 복사 금지
[000]bin은 DLL 1,772개 / EXE 187개를 공유하는 폴더다. 신규 산출물과 이름이 겹치는 DLL이 실측 기준 아래와 같다.
| DLL | 신규(.NET 10) | 기존(.NET FW) |
|---|---|---|
Oracle.ManagedDataAccess.dll |
5,434 KB | 4,602 KB |
Microsoft.Web.WebView2.*.dll ×3 |
— | — (ExcludeAssets="runtime" 로 제외됨) |
평면 복사하면 Oracle.ManagedDataAccess.dll이 덮여 레거시 EXE 187개 전부가 Oracle 접속 불능이 된다. 반드시 하위 폴더에 둔다. Information, Log, OCR서식생성기, SpreadDesign 등 기존 앱들도 같은 방식이다.
런타임 요구사항
FDD(framework-dependent)로 배포한다. 단말에 .NET 10 Desktop Runtime(Microsoft.WindowsDesktop.App 10.x)이 필요하다.
dotnet --list-runtimes | findstr WindowsDesktop.App
선례: [000]bin\OCR서식생성기\WindowsOCR.runtimeconfig.json이 이미 net10.0 + Microsoft.WindowsDesktop.App 10.0.0을 요구하며 운영 중이다. 런타임이 없는 단말이 발견되면 자체 포함으로 전환한다(산출물 8.6MB → 약 150MB).
pwsh tools/publish.ps1 -SelfContained
접속 정보 우선순위
환경변수 > appsettings.Development.json > appsettings.json > ServerInfo ini
- 병원 설치본: 위 세 가지가 모두 없거나 플레이스홀더(
__HOST__)이므로ServerInfo ini로 떨어진다.ResolveIniPath가 실행 폴더에서 상위로 최대 9단계 탐색하므로[000]bin\SheetMe\→[000]bin\MSYSTECH_ServerInfo.ini를 찾는다. - 개발 단말:
appsettings.Development.json(.gitignore대상, Debug 빌드에서만 산출물 복사). - 일회성 오버라이드: 환경변수
ConnectionStrings__His.
ini의 CurrentServer가 가리키는 DB로 고정 연결되며, 값은 레거시와 동일한 MD5 → 3DES-ECB 규약으로 복호한다(ServerInfoReader). 복호 결과와 완성된 접속 문자열은 로그·화면에 절대 기록하지 않는다.
⚠ SaveMode 기본값은 File
ini의 CurrentServer는 운영 병원 DB를 가리킨다. 그래서 DB 쓰기는 FormStore:SaveMode를 Db로 명시한 단말에서만 활성화된다. 이 기본값을 바꾸지 말 것.
기동 규약
SheetMe.Designer.exe "UidCod,ComNum,ShtCod"
콤마 구분 단일 인자다(레거시 M.EMR.SheetDesigner.exe와 동일). 필드가 모자라도 동작한다.
| 인자 | 의미 |
|---|---|
UidCod |
HIS 사용자 코드 — 감사 컬럼(SdgUidCod 등)의 출처. 없으면 DB 쓰기가 차단된다 |
ComNum |
내원번호 — 레거시에서도 쓰이지 않는 죽은 인자. 형상 보존용 |
ShtCod |
기동 시 자동으로 열 서식 코드. 비우면 서식 목록만 표시 |
예: SheetMe.Designer.exe "011825,,P163"
바로가기 배포
현재는 기록지정보 화면의 '서식생성기 연동' 버튼이 레거시를 띄운다(레거시 저장소 무수정 결정). SheetMe는 사용자별 바로가기로 기동한다 — UidCod가 감사 컬럼의 출처이므로 사용자마다 다른 인자가 필요하다.
대상: C:\MsystechHIS_Ver.2\[000]Bin\SheetMe\SheetMe.Designer.exe "011825,,"
시작 위치: C:\MsystechHIS_Ver.2\[000]Bin\SheetMe
인자 없이 실행하면 미인증 상태로 열리며, DB 읽기와 파일 저장은 되지만 DB 쓰기는 차단된다.
배포 후 확인
SheetMe.Designer.exe "<유효한UidCod>,,"실행 → 서식 목록이 뜨는지- 서식을 열고 저장하지 말고 닫기 → 정상 종료되는지
- 로그 폴더(
[000]bin\SheetMe\logs\Designer\)에 파일이 생기는지 - 화면 어디에도 접속 문자열·비밀번호가 노출되지 않는지
- 레거시 EXE가 멀쩡한지 — 기존 HIS 프로그램 하나를 띄워 DB 조회가 되는지 확인(평면 복사 사고 감지)
롤백
[000]bin\SheetMe 폴더 이름을 바꾸거나 지우면 끝난다. 레거시 산출물은 하나도 건드리지 않았으므로 다른 조치가 필요 없다.
아직 하지 않은 것
- LiveUpdate 편입 — 하위 폴더 지원 여부와 삭제 파일 정리 동작을 확인하지 못했다. 모르는 상태로 태우면 구 DLL이 남는 반쪽 갱신이 진단 불가 장애가 된다. 수동 zip 배포로 시작하고, 안정화 후
M.CMM.UpdateInfoFileGenerator.exe규격을 조사해 편입한다. - 단일 인스턴스 제어 — 같은 서식을 두 프로세스에서 열어 각각 저장하면 뒤에 저장한 쪽이 앞 내용을 이력으로 밀어낸다. 프로세스 내부는 막혀 있지만 프로세스 간에는 무방비다. 다중 사용자 병행 운영 전에 처리한다.