초기 커밋: SheetMe 서식생성기 (P0~P5 완료 상태)

레거시 서식생성기(VB.NET WinForms) 대체용 C#/.NET 10 WPF 디자이너.
기준선: 실DB 활성 디자인 1,271건 왕복 의미론 diff 0 / 예외 0, 단위 테스트 49/49.

이 커밋에 함께 포함된 자격증명 분리:
- appsettings.json 을 __HOST__/__PASSWORD__ 플레이스홀더로 전환
- 실접속 정보는 appsettings.Development.json 으로 분리(.gitignore 제외,
  csproj Debug 조건부 복사라 Release 산출물에 실리지 않음)
- ConfigLoader 를 환경변수 > Development > appsettings 순 레이어링으로 변경,
  미치환 플레이스홀더는 '미설정'으로 간주

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-11 17:20:22 +09:00
co-authored by Claude Fable 5
commit 16c07f48dc
102 changed files with 14210 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
# SheetMe 서식생성기 (C#/.NET 10 WPF)
MsystechHIS 레거시 서식생성기(`[003]EMR\[001]SheetDesigner`, VB.NET WinForms)를 대체하는 **신규 WPF 서식 디자이너**.
레거시 XML 포맷을 **읽기·쓰기 모두 무손실 호환**하여, 여기서 만든 서식을 기존 EMR 런타임(EMRLoader)이 그대로 렌더링한다.
## 프로젝트 구성
| 프로젝트 | TFM | 역할 |
|---|---|---|
| `src/SheetMe.Core` | net10.0 | 포맷 중립 모델(FormDocument) · **LegacyXmlSerializer**(읽기+쓰기, PropBag 무손실 왕복) · FormJsonSerializer(부 포맷) · ControlRegistry(팔레트/속성 스키마) |
| `src/SheetMe.Data` | net10.0 | Oracle 저장소 — **OracleLegacyFormStore**(E_ShtMst/E_SdgMst/E_SctMst, 레거시 동일 저장 의미론) · SctMstXmlWalker · EmrDataContext(M.MW.Data.EMR) |
| `src/SheetMe.Designer` | net10.0-windows | WPF MVVM 디자이너(M.Framework.WPF) — 캔버스/팔레트/인스펙터/페이지/레이어 |
| `tests/SheetMe.Core.Tests` | net10.0 | MSTest 44건 — 실서식 XML 왕복 의미론 diff 0 게이트 포함 |
## 실행
```powershell
dotnet build
dotnet run --project src/SheetMe.Designer
dotnet test
```
### 진단 모드 (자동 검증)
```powershell
# 첫 페이지 오프스크린 렌더 → PNG (레거시 시각 대조용)
SheetMe.Designer.exe --render-smoke <서식.xml> <출력.png>
# 편집 코어 자동 검증(선택/이동/리사이즈/마퀴/복붙/Undo/왕복) → 리포트
SheetMe.Designer.exe --edit-smoke <리포트.txt>
```
## 주요 기능 (v1)
- **캔버스 편집**: 클릭/Ctrl/Shift/마퀴 선택, 드래그 이동(스냅: 그리드+정렬 가이드, Alt=자유), 8핸들 리사이즈(다중선택 비례), 키보드 넛지, z-order, 정렬 6종
- **Undo/Redo**: 문서 스냅샷 메멘토 — 드래그=1스텝, 넛지 400ms 코얼레스
- **팔레트 14종**: Label·TextBox·MaskedTextBox·CheckBox·RadioButton·ComboBox·ListBox·CheckList·DateTimePicker·Panel·GroupBox·Line·PictureBox·CalcBox — 미지원 레거시 컨트롤(Spread/MSign 등)은 **자리표시로 무손실 보존**(이동/리사이즈 가능, 저장 시 원본 속성 전부 유지)
- **인스펙터**: 스키마 기반 속성 편집(다중선택 교집합), 폰트/색은 레거시 invariant 문자열 정합
- **페이지/레이어**: 페이지 추가/삭제/용지 크기, 레이어 목록(잠금/숨김)
- **그룹**: Ctrl+G/Ctrl+Shift+G — 그룹 멤버 클릭 시 그룹 전체가 한 단위로 선택/이동
- **컨테이너 자식 편집**: Panel/GroupBox 내부 컨트롤을 캔버스에서 직접 클릭·이동·리사이즈·삭제(상대좌표 유지)
- **미리보기/인쇄**: 편집 크롬 없는 렌더(캔버스와 동일 템플릿), FixedPage 1:1(DIP) 인쇄
- **파일**: 레거시 .xml 열기/저장(TK_ExportXML 호환) + JSON 가져오기/내보내기(부 포맷)
- **DB**: E_ShtMst 검색 → 활성 디자인 열기 · **DB 저장**(레거시 동일: ShtCneYon='Y'→제자리 갱신 / 그 외 SdgDelYon 버저닝 + E_SctMst 재생성, 시퀀스→MAX+1 채번, 단일 트랜잭션) · **신규 서식 등록**(미등록 코드 저장 시 자동 안내 — ShtTyp='D' 관행 기본값)
## 설정 (`src/SheetMe.Designer/appsettings.json`)
```json
{
"ConnectionStrings": { "His": "Oracle 접속 문자열" },
"FormStore": { "SaveMode": "File" } // DB 저장은 "Db" 로 명시 변경 시에만 활성(안전 게이트)
}
```
## 레거시 호환 규약 (정합성 기준: bzDesignSheetLoader.LoadObject 가 오류 없이 복원)
- XML: `<Sheet name="SheetDesignInfo">` 루트에 페이지당 `<Object>`(MDesignerHost) N개, 자식 Object 먼저 → Property 나중
- 타입: 레거시 AQN 원문 보존, 신규는 `M.EMR.UserControl.{Cls}, M.EMR.UserControl, Version=1.0.0.0, ...`
- 속성값: WinForms TypeConverter invariant 포맷(`"120, 88"`, `"굴림, 11.25pt, style=Bold"`, `"224, 224, 224"`)
- LocationOnBase 는 저장 시 재계산(부모 절대좌표 누적), `<Binary>` 는 verbatim 보존(신규 생성 안 함 — .NET 10 BinaryFormatter 제거)
- z-order: XML 첫 Object = 최상위(WinForms Controls 규약) ↔ WPF 캔버스는 역순 렌더
## 실DB 검증 결과 (2026-07-16, 테스트DB 192.168.100.222/MSYSTECHHIS)
- **읽기**: 전체 디자인 서식 1,271건 일괄 왕복(Read→Write) **의미론 diff 0 / 예외 0** — 미지원 컨트롤 보존 서식 242건 포함
- **쓰기**: S999 무변경 재저장 — 신규 버전 생성(SdgKey 52241→52380), 재저장본 diff 0, E_SctMst 36행 워커 기대치 일치, 이전 버전 `SdgDelYon='Y'` 이력 보존 확인
- 호환성 세부: 텍스트 내 CR 은 `NewLineHandling.Entitize`(&#xD; 보존), 레거시 데이터의 제어문자(0x05)는 `CheckCharacters=false` 관용 파싱(구식 XmlTextReader 동등)
## 계획 범위(P0~P5) 전체 완료 — 후속 아이디어
- 레거시 SheetDesigner/EMR 미리보기로 S999 육안 확인 (권장)
- v2 후보: 미지원 컨트롤 네이티브 지원(Spread 표, MSign 서명), 계산박스 수식 평가, 컨트롤 간 자식 드래그 재배치(reparent), 자 눈금(룰러), REST API 경유 모드
설계 계획서: `C:\Users\Msystech\.claude\plans\c-net-wpf-flickering-gizmo.md`