Files
SheetMe/docs/DEPLOYMENT.md
MsystechandClaude Fable 5 71862c2986 배포 준비 — 자격증명 분리, 산출물 축소, 로깅·전역 예외
[자격증명] 접속 문자열 우선순위를 환경변수 > 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>
2026-08-11 19:23:27 +09:00

109 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SheetMe 배포 가이드
## 요약
```bash
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`)이 필요하다.
```bash
dotnet --list-runtimes | findstr WindowsDesktop.App
```
선례: `[000]bin\OCR서식생성기\WindowsOCR.runtimeconfig.json`이 이미 `net10.0` + `Microsoft.WindowsDesktop.App 10.0.0`을 요구하며 운영 중이다. 런타임이 없는 단말이 발견되면 자체 포함으로 전환한다(산출물 8.6MB → 약 150MB).
```bash
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 쓰기는 차단**된다.
---
## 배포 후 확인
1. `SheetMe.Designer.exe "<유효한UidCod>,,"` 실행 → 서식 목록이 뜨는지
2. 서식을 열고 **저장하지 말고** 닫기 → 정상 종료되는지
3. 로그 폴더(`[000]bin\SheetMe\logs\Designer\`)에 파일이 생기는지
4. 화면 어디에도 접속 문자열·비밀번호가 노출되지 않는지
5. **레거시 EXE가 멀쩡한지** — 기존 HIS 프로그램 하나를 띄워 DB 조회가 되는지 확인(평면 복사 사고 감지)
---
## 롤백
`[000]bin\SheetMe` 폴더 이름을 바꾸거나 지우면 끝난다. 레거시 산출물은 하나도 건드리지 않았으므로 다른 조치가 필요 없다.
---
## 아직 하지 않은 것
- **LiveUpdate 편입** — 하위 폴더 지원 여부와 삭제 파일 정리 동작을 확인하지 못했다. 모르는 상태로 태우면 구 DLL이 남는 반쪽 갱신이 진단 불가 장애가 된다. 수동 zip 배포로 시작하고, 안정화 후 `M.CMM.UpdateInfoFileGenerator.exe` 규격을 조사해 편입한다.
- **단일 인스턴스 제어** — 같은 서식을 두 프로세스에서 열어 각각 저장하면 뒤에 저장한 쪽이 앞 내용을 이력으로 밀어낸다. 프로세스 내부는 막혀 있지만 프로세스 간에는 무방비다. 다중 사용자 병행 운영 전에 처리한다.