docs: define MSIX-first packaging design and roadmap
Document package formats, release workflows, deployment planning and UI concepts. Closes #1
This commit is contained in:
1 parent
54f0cfe360
commit
24b624301c
37 files changed
+7061
-61
No files matched your search
@@ -0,0 +1,171 @@
|
||||
# 범용 설치 패키지 제작기 구현 백로그
|
||||
|
||||
작성일: 2026-10-19. [검토 결과](../plan/09-plan-review.md)와 [단독 개발 일정](../plan/10-development-schedule.md)을 함께 사용한다. 백로그는 저장소 문서로만 관리하며 Gitea 이슈는 생성하지 않는다.
|
||||
|
||||
## 현재 범위 — MSIX 우선, 기준선 v3
|
||||
|
||||
첫 제품은 **MSIX 생성·서명·직접 배포 업데이트 설정·제작 GUI/CLI**다. EXE/MSI/MSP·HTML 설치 마법사·EG-BIM 전환·자체 그룹 배포 서버·Store 제출은 후속으로 이월한다. [현재 설계](../code-design/12-msix-first-builder.md), [변경 기록](../changes/2026-10-19-msix-first.md) 참조.
|
||||
|
||||
기존 53개 ID는 유지하며 **1차 18개 / 후속 35개**로 구분한다. 모든 구현 작업은 미착수다. 시안은 구현 완료 증빙이 아니다. 표의 P0/P1은 해당 개발 단계 안의 우선순위이며 후속 P0가 첫 MSIX 출시를 막지 않는다.
|
||||
|
||||
| 개발 단계 | 백로그 ID | 완료 기준 |
|
||||
| --- | --- | --- |
|
||||
| 1차 MSIX | BL-02, BL-03, BL-06, BL-09~11, BL-14, BL-16, BL-29, BL-41, BL-46~53 | MS0~MS6. 두 독립 제품의 MSIX 설치/업데이트/제거까지 검증 |
|
||||
| 후속 EXE·전환·배포 | BL-01, BL-04~05, BL-07~08, BL-12~13, BL-15, BL-17~28, BL-30~40, BL-42~45 | 후속 일정 미배정. 기존 요구를 보존하되 완료 처리하지 않음 |
|
||||
|
||||
BL-02/03/06의 WiX·타사 EG-BIM PE·그룹 배포 추가 검증은 후속 관련 작업으로 넘긴다. BL-10의 EXE v1 가져오기는 후속 EXE 단계의 인수 기준이다. BL-50에서 공통 서명·불변 저장을 먼저 구현하고 BL-19/20에서 EXE 전용 순서와 기준 저장소를 확장한다. BL-53은 현재 **MSIX 제품 완료 게이트**이며 두 형식 통합 회귀는 후속 BL-17/28에서 추가한다.
|
||||
|
||||
## 운영 규칙
|
||||
|
||||
- **인력/산정 기준:** 개발자 1명, AI 코딩·설계·테스트·문서화 지원 없음. 개발자가 시험과 배포 운영 준비도 수행한다. 외부 승인자·테스터는 추가 개발 인력이 아니다.
|
||||
- **우선순위:** P0는 선행 위험 해소·데이터 보존·배포 차단 조건, P1은 해당 단계 완성의 필수 기능, P2는 선택적 확장이다. 1차 P1을 임의로 제외해 첫 제품 완료로 표시하지 않는다.
|
||||
- **상태:** 아래 모든 항목은 `미착수`. 이후 `진행 중 → 검증 중 → 완료`로 갱신한다. `차단`은 원인·필요 자료·해제 조건을 함께 기록한다. 시안과 설계 작성은 구현 완료 증빙이 아니다.
|
||||
- **선행 조건:** 표의 ID는 완료 후 착수하는 기본 순서다. 인터페이스 검토·자료 수집은 먼저 할 수 있지만 선행 구현의 시험을 통과한 것으로 취급하지 않는다. 외부 전제는 ID 외에도 명시했다.
|
||||
- **작업 한도:** 구현 항목은 동시에 1개만 진행한다. 외부 답변 대기 중에는 선행 조건이 충족된 다른 항목을 선택한다. 큰 항목은 착수 전에 1~5일 작업으로 나누되 부모 ID와 완료 기준을 유지한다.
|
||||
- **공통 완료 기준:** 변경 코드/문서, 의미 있는 자동 검사, 필요한 Windows VM 실험, 실패 경로, 로그/비밀정보 점검, 사용 절차를 연결한다. 실행하지 않은 검사는 `notRun`으로 남기며 완료를 선언하지 않는다. 시험 기록은 아티팩트 해시·기준 상태·도구/OS·기대/실제 결과를 포함한다.
|
||||
- **외부 자료:** 실제 제품 바이너리·고객 설정·서명 키는 공개 Git 저장소에 올리지 않는다. 승인된 별도 저장 위치와 식별자·해시·접근 절차만 연결한다.
|
||||
|
||||
현재 마일스톤은 `MS0~MS6`다. 이전 `M0~M10/M-MSIX` 일정은 대체했으며 후속 작업의 과거 단계 이름으로 사용하지 않는다. 담당은 별도 표시가 없으면 단독 개발자이며, 계약·제품 승인·테스터 참여는 관련 외부 주체의 협조가 필요하다. 작업별 예상 일수는 M0에서 실측 자료를 확보한 뒤 세분화한다.
|
||||
|
||||
## A. 기준 확정과 위험 실험 — 기준
|
||||
|
||||
근거: [현황](../plan/01-requirements-and-current-state.md), [전환](../plan/02-installer-migration.md), [패치](../plan/08-version-patching.md), [설치 UI](../code-design/09-install-flow-and-ui.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-01 | P0 | 실제 출시본·payload·런타임 인벤토리 | 실제 배포본/소스 접근 | 지원 후보별 EXE/MSI 해시·GUID·버전·언어·아키텍처·경로와 제거 작업 목록 작성. 실제 배포 파일/사용자 데이터/타사 파일을 구분하고 제조사·런타임 재배포 조건의 확인 여부 기록. |
|
||||
| BL-02 | P0 | 도구·지원 환경과 MSIX 위험 실험 | 없음 | Windows SDK MakeAppx/SignTool, Rust/Tauri, 최소 Windows/CPU 조합과 도구 해시 고정. 작은 Win32 앱으로 MSIX 생성·서명·실행·업데이트 재현. WiX/Burn은 요구하지 않음. 지원 범위/학습 공수를 MS0에서 재산정. |
|
||||
| BL-03 | P0 | MSIX 서명·게시자·신뢰 정책 | BL-46 | 개발/운영 서명 프로필, Publisher/Subject 일치, 대상 PC 신뢰, 타임스탬프·갱신·비밀 저장 정책 확정. 실제 운영 서명 접근의 차단 조건 기록. EG-BIM·EXE 서명은 후속. |
|
||||
| BL-04 | P0 | 지원 기준 상태·전체 대체 정책 | BL-02, BL-46 | 실제 지원할 legacy 목록과 WiX 기준 상태 목록 정의. 신규 설치 상태/패치 도달 상태를 구분하고 보존 기간, Minor/Major 경로, 패치 제거 기본 비활성 정책 문서화. 공통 MSI 기준 상태는 가상 제품으로 확정; EG-BIM legacy 지원 목록은 BL-01 이후 별도 확정. |
|
||||
| BL-05 | P0 | 서버·장치·기존 채널 계약 | 없음 | 사내망/인터넷, 저장소/DB/인증 방식과 용량 가정 결정. Center/Family/External의 의미, 장치 그룹 충돌·최초 등록·오프라인 라이선스 경로 결정. |
|
||||
| BL-06 | P0 | MSIX 인수 기준·VM 매트릭스 | BL-02, BL-46 | 두 독립 가상 제품과 지원 OS/CPU/권한별 설치·실행·버전 증가·제거·데이터 보존 기준 확정. 불일치 인증서·누락 의존성·디스크 부족·중단·네트워크 실패와 설치 중 사용 상태 포함. Store·EXE·그룹 테스터 요구 없음. |
|
||||
| BL-07 | P0 | 기존 제거와 설정 보존 실험 | BL-01, BL-02 | 스냅샷 VM에서 실제 구버전 제거 전후 파일·HKCU/HKLM·CAD 연결 차이를 측정. 다른 계정 UAC·사용자 지정 경로를 포함해 외부 백업의 복원 가능성과 미복구 범위를 기록. |
|
||||
| BL-08 | P0 | Rust/Burn BA·UI 부트스트랩 실험 | BL-02 | Detect/Plan/Apply·취소·오류·재부팅 이벤트의 최소 연결을 재현. WebView2 없는 오프라인 VM에서 시작 경로 확인. 미성립 시 native 선행 UI 등 대안과 추가 공수를 결정하고 자유 UI 약속을 보류. |
|
||||
|
||||
## B. Rust 공통 엔진과 CLI — 공통
|
||||
|
||||
근거: [구조](../code-design/01-architecture.md), [데이터](../code-design/02-project-model.md), [파일/레지스트리](../code-design/03-files-and-registry.md), [식별자](../code-design/04-version-and-identity.md), [명령](../code-design/07-ui-and-commands.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-09 | P1 | Rust workspace·Windows CI·fixture | BL-02 | domain/engine/infra/cli 의존 방향과 잠금 파일 구성. 새 환경에서 format/lint/build/test 실행, 소형 가상 제품 준비. 로컬 설정·작업 폴더·대형 산출물을 형상 관리에서 제외. |
|
||||
| BL-10 | P0 | v2 MSIX 프로젝트·저장·검증 | BL-09, BL-46 | Rust/JSON Schema 일치, 미지 필드/버전·revision 충돌·백업 검증. formats.exe 없이 MSIX 프로젝트 열기/저장. EXE/v1/Store 미지원 입력은 설명과 함께 거부하고 자동 변환하지 않음. 확정되지 않은 identity·서명으로 정식 결과 확정 불가. |
|
||||
| BL-11 | P0 | 파일 해석과 스냅샷 입력 | BL-10 | 포함/제외·필수 파일·정렬 결과가 결정적. 대소문자 충돌, 경로 탈출/ADS/reparse point, 출력 재수집 차단. 스트림 복사·해시, 복사 중 원본 변경 탐지, 원본 무변경 확인. |
|
||||
| BL-12 | P0 | 버전·GUID·identity lock | BL-04, BL-10, BL-11 | 제품/패키지/패치/컴포넌트 식별자의 수명·tombstone·예약 이력 구현. MSI 버전 경계 및 PE 표시 버전 매핑 검사. 같은 리소스의 안정적 GUID와 동시 확정 차단 확인. |
|
||||
| BL-13 | P1 | 레지스트리·설치 위치 컴파일 | BL-10, BL-12 | 타입·뷰·literal/formatted 값을 검증하고 WXS에 안전하게 직렬화. 기존 경로 보존, 소유한 값만 제거, 미지원 HKCU 정책 차단. 생성기 PC 레지스트리가 바뀌지 않음을 확인. |
|
||||
| BL-14 | P0 | 프로세스·작업·중단 복구 | BL-09, BL-10 | 허용 도구/인자 배열·시간 제한·Job Object·OS 잠금 구현. GUI/CLI 중복 실행 차단, 취소 시 자식 종료, Interrupted 복원, 재개 전 입력/완료 산출물 해시 재검사. |
|
||||
| BL-15 | P0 | 설치 단계 카탈로그·검증기 | BL-10, BL-13 | 모드/phase/조건 타입·의존 그래프 검증. 순환·필수 백업 삭제·권한 없는 핸들러·미지원 모드 차단. 화면 숨김과 실행 단계 제거를 구분하고 무인 설치 필수 입력 검사. |
|
||||
| BL-16 | P1 | MSIX 공통 계획 서비스와 CLI | BL-11, BL-14, BL-47 | validate/plan/build/job/export 계약·종료 코드·JSON 출력. 오래된 revision/도구/identity 계획과 중복 요청 차단. 실제 빌드·내보내기는 BL-49/50에서 연결. patch/MSI/EXE/Store 요청은 명시 오류. |
|
||||
|
||||
## C. 전체 설치·서명·구버전 전환 — 후속 EXE와 공통 VM
|
||||
|
||||
근거: [릴리스](../code-design/05-release-pipeline.md), [전환](../plan/02-installer-migration.md), [서명](../plan/06-code-signing-and-smartscreen.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-17 | P0 | WiX MSI/Burn 전체 설치 생성 | BL-02, BL-16, BL-47 | 실제 MSI 테이블/식별자와 기대 계획 일치. 기본·사용자 지정 경로, 필수 런타임, silent·오프라인·재부팅, repair/uninstall의 소형 제품 시험 통과. CLI build 연결. 직접 배포용 offline-singlefile/offline-layout/network 출력과 불변 payload 검증. 후속 완료 시 두 독립 제품의 EXE와 기존 MSIX 비회귀 확인. |
|
||||
| BL-18 | P0 | 대용량 CAB·출력 한계 검사 | BL-17 | 실제에 가까운 압축률로 총 2GB 초과 레이아웃 설치/복구 확인. 개별 파일 초기 지원 한계·단일 EXE 크기/서명 불가를 명확히 차단. 임시 공간 포함 계산과 메모리 사용 측정. |
|
||||
| BL-19 | P0 | 운영 서명·타임스탬프 어댑터 | BL-03, BL-17, BL-50 | 자체/타사 PE 구분, CAB/MSI/Burn 서명 순서와 최종 해시 검증. 서명·타임스탬프 실패 시 배포 불가, 완료 파일 재서명 방지. 실제 운영 서명과 개발 인증서 결과를 분리. BL-50의 공통 서명 포트를 EXE 순서로 확장. |
|
||||
| BL-20 | P0 | EXE 기준 릴리스·증빙 저장 확장 | BL-18, BL-19, BL-50 | 동일 releaseId 덮어쓰기 차단, MSI/wixpdb/서명 payload/정의/도구/로그 보존. Finalized와 설치 시험 증빙 분리, 결과 상태를 실제 파일에서 추출. 증빙 없는 정식 배포 준비 상태 차단. BL-50의 불변 저장 계약을 재사용. |
|
||||
| BL-21 | P0 | 사용자별 백업·검증·복원 | BL-14 | 원래 사용자 SID 기준 CUI/설정/추가 리소스 보관 및 호환 설정만 복원. 여러 프로필·다른 관리자 UAC·부분 실패 결과를 호출자에 전달. 임시 다운로드 정리와 백업 수명 분리. 공통 계약은 가상 사용자 데이터로 검증. EG-BIM 실제 보존 정책은 BL-07 검증 후 적용. |
|
||||
| BL-22 | P0 | 실제 EG-BIM 전환 실행 | BL-15, BL-20, BL-21 | 전체 payload 확보·백업 검증 전 구버전 제거 차단. 지원 legacy별 기존 경로·타사 CAD 연결·사용자 데이터 보존 및 앱 실행 확인. 실패/전원 중단 시 복구 상태·로그·백업 유지. |
|
||||
| BL-41 | P0 | VM 시험 실행·증빙 수집 기반 | BL-02, BL-09 | 업무 PC와 분리된 지원 OS VM/스냅샷·fixture·로그 수집 구성. 첫 패키지부터 실제 아티팩트 해시와 기준 상태로 증빙 저장. 이후 단계마다 신규/패치/실패 시험 매트릭스를 누적 실행. 기반은 MS1에 준비하고 각 게이트에서 재사용. |
|
||||
|
||||
## D. 패치와 적용 실행 계약 — 후속 EXE
|
||||
|
||||
근거: [패치 운영](../plan/08-version-patching.md), [패치 생성](../code-design/06-patch-pipeline.md), [검증](../code-design/08-validation-and-roadmap.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-23 | P0 | 기존 업데이터 실행 능력 검증 | BL-02 | NuGet 구현/테스트로 MSI/MSP 실행·승격·서명 검증·종료 코드·재부팅·동시 실행 지원을 확인. 재사용 가능/별도 구현 필요 항목과 API 계약 작성. 조사부터 먼저 착수할 수 있으나 완료는 실제 실행 증빙 필요. 공통 실행 어댑터는 가상 제품으로 검증하며 EG-BIM NuGet 적합성은 BL-01 이후 별도 적용 결과로 기록. |
|
||||
| BL-24 | P0 | 설치 시도 상태 머신 | BL-21, BL-23 | attemptId·잠금·원래 사용자·3010/1641·재부팅 후 재개·rollback 완료/불명확 상태 구분. 앱 저장/종료 실패 시 적용 차단, 불명확 상태에서 전체 설치 강행 차단. |
|
||||
| BL-25 | P0 | baseState 저장·diff·호환성 | BL-04, BL-12, BL-20 | ProductCode/PackageCode·언어·아키텍처·패치 이력·관리 파일로 기준 식별. 신규 설치와 패치 도달 상태 분리. 삭제/이동/런타임 구조 변경을 FullUpgradeRequired로 분류하고 사용자 데이터를 비교 대상에서 제외. |
|
||||
| BL-26 | P0 | MSP 생성·서명·불변 보관 | BL-19, BL-25 | 한 기준 상태→한 목표 MSP 생성 및 실제 PatchCode/family/sequence 검증. 목표 PE 재서명 없음. 중복/역행 패치 차단, 크기 비교, 선언된 기준과 최종 해시 보관. |
|
||||
| BL-27 | P0 | Burn/MSP 및 전체 대체 경로 | BL-17, BL-24, BL-26 | 패치 후 ARP/Burn/MSI 버전·repair·제거·다음 업데이트 일관성 확인. 같은 ProductCode와 major 전환을 구분하고 source state별 동일 목표 전체 경로 검증. 미검증 경로는 FullUpgradeRouteUnavailable. |
|
||||
| BL-28 | P0 | 패치 기준별 동등성·실패 시험 | BL-17, BL-26, BL-27, BL-41 | 최소 두 선언 기준 상태에서 목표 신규 설치와 공급자 관리 상태 비교. 중간 버전 생략·중복·파일 수정/누락·원본 캐시 누락·디스크 부족·중단·재부팅·복구/제거/다음 패치 시험. 선언한 모든 기준의 증빙 통과. 공통 게이트는 가상 제품 기준이며 실제 EG-BIM 전환 기준 시험은 BL-22 이후 BL-42에서 확인. 후속 두 형식 설치/업데이트 회귀를 추가하되 MSIX에 MSP 적용 금지. |
|
||||
|
||||
## E. Tauri 제작기와 최종 설치 UI — 제작기와 후속 EXE UI
|
||||
|
||||
근거: [제작기 UI/명령](../code-design/07-ui-and-commands.md), [설치 과정/UI](../code-design/09-install-flow-and-ui.md).
|
||||
|
||||
2026-10-19 [재설계](../code-design/10-installer-wizard-redesign.md)에 따라 아래 작업을 구체화한다. 시안 작성으로 구현 상태는 변경하지 않는다. [변경 기록](../changes/2026-10-19-installer-ui-redesign.md) 참조.
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-29 | P1 | MSIX 제작기 화면·IPC·자체 배포 준비 | BL-16, BL-49 | 앱 정보·파일·패키지·서명·업데이트·검증/빌드 화면과 작업 이력. CLI와 같은 엔진, 작업 재연결, 최소 권한·경로 검증. 제작기 자체 배포 identity는 고객 앱과 분리. 선택한 단일 디자인 구현, WiX/EXE 출력 구현 없이 개발 환경 시작 및 배포/실행 확인. |
|
||||
| BL-30 | P1 | 설치 과정 편집기 | BL-15, BL-29 | 단계 추가/활성화/허용 순서/조건/등록 핸들러 속성 편집. 필수 단계 삭제와 의존성 오류를 저장/빌드에서 검사, 모드별 실행 계획 표시. 임의 관리자 셸 입력 기능 없음. |
|
||||
| BL-31 | P1 | 기본 테마·문구·리소스 편집 | BL-17, BL-29 | 고정 템플릿·로고·지원 색상/배치·문구/다국어 편집과 모드 미리보기. 실제 native 출력 비교, 미지원 자유 페이지 기능 명시. 변경 시 새 빌드/서명 필요성 반영. |
|
||||
| BL-32 | P1 | 사용자 정의 BA·자유 페이지 편집 | BL-08, BL-24, BL-30, BL-31 | 승인된 UI 백엔드로 입력 바인딩·검증·페이지/조건 분기·Feature 선택 구현. Burn 외 중복 설치 실행 없음, 적용 시작 후 계획 고정, 무인 입력 계약과 WebView2 부트스트랩 검증. 기본 테마 기능으로 대체 완료하지 않음. |
|
||||
| BL-33 | P1 | UI 실물 검증과 접근성 | BL-29~32, BL-41 | DPI·키보드·스크린 리더·다국어 및 오류/취소/실패/재부팅 화면 확인. 미리보기와 서명 번들 차이를 기록. patch/repair의 Feature 유지 및 대화형/무인 설치 결과 동등성 통과. |
|
||||
|
||||
### 재설계에 따른 추가 인수 기준
|
||||
|
||||
| 작업 | 기존 완료 기준에 추가할 검사 |
|
||||
| --- | --- |
|
||||
| BL-15 | welcome/license/options/review/prepare/apply/result 페이지와 실행 그래프를 분리. 업데이트의 약관 버전 조건, 필수 준비 및 무인 동의/입력 계약 검사. |
|
||||
| BL-24 | 적용 전 취소, 적용 중 취소 요청, 엔진이 확인한 rollback 결과, 상태 불명확, 재부팅 필요를 구분하고 UI에 전달. |
|
||||
| BL-30 | 모드별 단계 목록·조건/복구 속성과 잠금 규칙 편집. 화면 숨김이 백업/무결성 제거로 이어지지 않음. |
|
||||
| BL-31 | 진행 안내형/표준 마법사형의 지원 범위 검증. 페이지 목록·미리보기·속성 패널, 로고/문구/지원 스타일 편집. 미지원 native 매핑을 명시. |
|
||||
| BL-32 | 신규/전환/패치/복구/제거 페이지 분기와 이전 이동 시 입력 유지. review에서 계획 고정, apply의 이전 이동 차단, 제거 확인·약관 동의 차단. 검토용 상황 선택기는 배포 화면에서 제외. |
|
||||
| BL-33 | 두 외형에서 정상·백업 실패·실행 앱·적용 실패·취소·재부팅을 검증. 백업 전 제거 불가, 상태 불명확 시 무조건 재설치 불가, 재부팅 필요 시 앱 실행 숨김, 종료/재부팅 기본값 확인. |
|
||||
|
||||
## F. 서버·업데이터·단계 배포 — 후속 서버
|
||||
|
||||
근거: [패키지/업로드](../plan/03-package-and-upload.md), [단계 배포](../plan/04-staged-rollout.md), [패치](../plan/08-version-patching.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-34 | P0 | 내보내기·서버 수신·신뢰 계약 | BL-05, BL-20, BL-25, BL-50 | artifacts/dependsOn·적용 경로·증빙 스키마를 고정하고 모든 CAB/런타임 의존 관계 포함. Finalized/DeploymentReady와 Uploaded/Verified/Ready의 의미를 매핑. 메타데이터 서명·만료·키 교체·다운그레이드/재생 방지 정책과 클라이언트 검증 계약 결정. format별 identity/업데이트 경로를 구별하고 MSIX에 MSP 실행 경로를 제공하지 않음. |
|
||||
| BL-35 | P1 | 임시 업로드·검증·릴리스 등록 | BL-34 | 중단/재개·해시/서명/누락 검증·중복 릴리스 거부. 검증 실패는 격리, 불변 URL 등록, 준비 증빙 없는 Ready 차단. 업로드/승격 권한 분리와 감사 기록. |
|
||||
| BL-36 | P0 | 인증·장치 그룹·대상 선택 API | BL-05, BL-35 | 사용자 주장만으로 테스트 그룹 진입 불가, 최초 장치 등록·다중 사용자 충돌 정책 구현. 그룹 목표 결정 후 현재 상태에 맞는 승인 경로 선택. 사용자별 응답 캐시 격리·패키지 다운로드 접근 통제. |
|
||||
| BL-37 | P0 | 네트워크 설치·업데이터 연결 | BL-24, BL-27, BL-34, BL-36 | WebSetup의 고정 payload 경로와 사용자 목표 선택 책임 분리. 재개/프록시/만료 URL·해시/서명/메타데이터 검증 후 실행. 적용 직전 허가 재확인, 오프라인 라이선스의 전체 설치 경로 시험. 서버 장애 시 기존 앱 사용 유지. |
|
||||
| BL-38 | P1 | 설치/실행 결과 수집·집계 | BL-06, BL-24, BL-36 | attemptId+이벤트 순서로 중복 제거·오프라인 재전송. 다운로드/취소/재부팅/미응답/실행 실패 별도 집계. 기준→목표별 패치 실패와 전체 복구 성공을 구분하고 개인정보 최소 수집/보존 정책 적용. |
|
||||
| BL-39 | P0 | 수동 승인·중지·정책 충돌 | BL-06, BL-36~38 | 승인자·관측 증빙·정책 revision으로 4단계 승격. 릴리스 전체 중지와 패치만 중지를 구분하고 미승인 전체 경로 우회 차단. 적용 전 차단/시작 후 강제 종료 없음 확인. 필요 최소 CLI/API 제공, 복잡한 운영 UI는 제외. |
|
||||
| BL-40 | P1 | 보존·정리·복원 운영 | BL-04, BL-20, BL-35 | 현재/복구/진행 설치/지원 패치의 참조 자료 삭제 차단. 정리 계획 미리보기와 승인 이력, 저장소·메타데이터 백업 복원 시험. 서명 payload와 기준 MSI 누락 탐지. |
|
||||
|
||||
## G. 출시 검증과 운영 인수 — 후속 적용
|
||||
|
||||
근거: [필수 검증](../plan/07-implementation-and-validation.md), [관측/승격](../plan/04-staged-rollout.md), [개발 일정](../plan/10-development-schedule.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-42 | P0 | 전체 경로 회귀와 4단계 파일럿 | BL-06, BL-28, BL-33, BL-37~41, BL-43 | 실제 legacy→WiX→MSP→후속 업데이트와 설치 후 인증/도면/출력/플러그인 회귀 통과. 개발자→1차→2차→일반 사용자 단계마다 동일 아티팩트 해시·기준별 표본/실행/장애 지표로 승인. 표본 부족/중대 장애 시 보류. |
|
||||
| BL-43 | P0 | 운영 절차·릴리스 체크리스트 | BL-03, BL-06, BL-22, BL-28, BL-39, BL-40 | 서명 장애·중지·복구·재부팅 대기·지원 문의·데이터 보존 절차 작성 및 모의훈련. 수정 릴리스와 일반 다운그레이드 금지 원칙 반영. 개발자 본인 검증과 외부 업무 사용자 승인 기록 분리. |
|
||||
|
||||
BL-42는 후속 EG-BIM 종합 시험부터 일반 공개까지 이어지는 상위 작업이다. 단계별 증빙을 남기며 최종 승격 전에는 항목 전체를 완료 처리하지 않는다. BL-41의 기반 구축은 MS1, 후속 회귀 실행은 각 마일스톤의 시험 시간에 포함한다.
|
||||
|
||||
## H. Microsoft Store — 별도 선택 일정
|
||||
|
||||
근거: [Store 계획](../plan/05-microsoft-store.md), [출력 프로필](../code-design/05-release-pipeline.md).
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-44 | P2 | 제품별 Store 제출 적합성 판정 | BL-53 | 등록할 제품의 EXE 또는 MSIX 적합성, 계정·권리·정책 확인. EXE는 단일 오프라인/무인/서명, MSIX는 Store identity·capability·의존성 검증. 미지원 제품 전환 비용은 별도 산정. MSIX 출력 구현을 이 작업으로 미루지 않음. |
|
||||
| BL-45 | P2 | Store 제출·자체 업데이트 연계 | BL-44 | EXE는 고정 HTTPS URL·무인 인자, MSIX는 패키지 업로드·Store identity·Store 업데이트 경로로 제출. 대상 제품의 설치/업데이트 증빙 필수; EG-BIM을 제출할 때만 BL-42 적용 증빙 추가. 실제 제출·심사·공개 상태 구분, 미승인 결과를 공개 완료로 표시하지 않음. |
|
||||
|
||||
## I. MSIX 필수 기능 — MS0~MS6
|
||||
|
||||
근거: [범용 EXE·MSIX 구조](../code-design/11-generic-exe-msix-architecture.md). 기존 작업의 공통 필드·서명·VM 기반을 재사용하되 EXE 규칙을 MSIX에 강제하지 않는다.
|
||||
|
||||
| ID | 우선순위 | 작업 / 산출물 | 선행 조건 | 완료 기준 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| BL-46 | P0 | MSIX 우선 범위·제품 계약 | 없음 | 1차 MSIX/직접 배포, 후속 EXE/Store·HTML UI 경계 확정. format/delivery/distribution 모델은 유지. EG-BIM·Store·자체 인증 서버 없이 가능한 계약과 두 가상 제품 정의. |
|
||||
| BL-47 | P0 | PackageBackend·MSIX 작업 조정기 | BL-10, BL-14, BL-46 | 1차 MsixBackend 포트와 대상별 검증/계획/결과/잠금 구현. MSIX-only에는 MSI 필드를 요구하지 않음. 직렬 다중 대상의 부분 실패·불변 결과 보존·새 buildId 재시도 검증. EXE/Store는 UnsupportedTarget. |
|
||||
| BL-48 | P0 | MSIX manifest·identity·호환성 검사 | BL-11, BL-47 | Name/Publisher/4부분 Version/Architecture·최소 OS·실행 항목·자산·의존성·허용 capabilities 검증. MSI GUID 불필요, 임의 설치 경로·미지원 작업과 잘못된 Store identity 차단. |
|
||||
| BL-49 | P1 | MakeAppx MSIX 생성 백엔드 | BL-02, BL-14, BL-48 | 고정 SDK로 staging→manifest→pack→내용/identity 검사. 검증 우회 금지, 원본 무변경, 누락 파일/자산·취소·디스크 부족 실패 기록. `.msix` 필수, bundle은 후속 범위. |
|
||||
| BL-50 | P0 | MSIX 서명·불변 결과·내보내기 | BL-03, BL-14, BL-49 | 직접 배포 Publisher/인증서 일치·서명/신뢰·해시 검사. 개발/운영/미서명 상태, Finalized/DeploymentReady 분리. 동일 releaseId 덮어쓰기 금지, manifest·SDK·입력·패키지·로그·보고서 보존/내보내기. 인증서/타임스탬프 실패와 재시도 검증. EXE 저장소·Store 제출 프로필은 후속. |
|
||||
| BL-51 | P1 | MSIX 업데이트·App Installer | BL-50, BL-41 | 상위 버전 전체 MSIX와 HTTPS App Installer 생성/검증. 파일 안내 URI와 버전별 패키지 URI·서명/identity·OS/스키마 조건 확인. 실행 중 업데이트·재시도·버전 건너뛰기·데이터 보존/제거 시험. Windows 차등 경로와 전체 선다운로드 차이를 기록. 인증/그룹 서버·EXE 전환은 후속. |
|
||||
| BL-52 | P1 | MSIX 제작 UI·CLI 완성·접근성 | BL-29, BL-48, BL-50 | 1차 MSIX 설정만 노출하고 직접 배포/자동 업데이트 사용 설정. 실제 파일/자산/의존성/서명 프로필 편집과 출력 폴더 선택. 잘못된 버전·Publisher·실행 파일·URI의 원인/위치 안내. DPI·키보드·스크린 리더·취소/중단/재연결·긴 작업 UI·GUI/CLI 동등성 검증. HTML 설치 마법사 불필요. |
|
||||
| BL-53 | P0 | MSIX 제품 완료·회귀·사용 안내 | BL-06, BL-16, BL-41, BL-48~52 | 두 독립 가상 제품 각각 MSIX 생성·실제 서명·직접 설치·실행·상위 버전 업데이트·제거·앱 데이터 정책 검증. 부분 실패·미서명/개발 결과 제한·원본 무변경·누락 런타임/자산·Publisher 오류 시험. 불변 증빙과 사용자 가이드/운영 절차 제공. EXE·Store·EG-BIM·자체 그룹 서버 없이 MS6 통과. |
|
||||
|
||||
## 첫 착수 순서
|
||||
|
||||
1. BL-46/02/03/06: MSIX 범위·도구·서명·설치/업데이트 실험과 완료 기준.
|
||||
2. BL-09/10/11/14/47/16/41: 공통 모델·입력·작업 엔진·CLI·VM 기반.
|
||||
3. BL-48/49: manifest와 실제 MSIX 생성.
|
||||
4. BL-50: 서명·불변 결과·직접 배포 내보내기.
|
||||
5. BL-51: App Installer 업데이트와 실제 적용 검증.
|
||||
6. BL-29/52: 제작기 GUI와 IPC·실파일 편집·접근성.
|
||||
7. BL-53: 두 제품 회귀와 MS6 출시 준비.
|
||||
|
||||
후속 35개 항목에는 날짜를 배정하지 않는다. 현재 작업의 필수 의존성이 후속 항목을 참조하지 않는지 변경마다 검사한다. 재개할 때 EXE/BA·실제 제품·서버/Store 범위를 다시 산정한다.
|
||||
@@ -0,0 +1,29 @@
|
||||
# 범용 제작기 범위 정정과 EXE·MSIX 필수 출력
|
||||
|
||||
날짜: 2026-10-19. 상태: 사용자 의도 반영, 설계/백로그 수정 완료. 구현과 실제 패키지 시험은 미착수다.
|
||||
|
||||
## 변경 이유와 결정
|
||||
|
||||
사용자는 범용 설치 프로그램을 개발하며, 이 프로그램이 만든 EXE나 MSIX를 필요에 따라 Microsoft Store에 등록하려 한다. 기존 문서는 EG-BIM 설치기 전환을 제품 전체의 목적으로 두고 MSIX를 선택 확장으로 분류했다. 이 해석을 바로잡는다.
|
||||
|
||||
- 제품은 여러 Windows 앱을 위한 설치 패키지 제작기다. EXE와 MSIX 백엔드를 모두 필수 제공하고 프로젝트별로 하나 또는 둘을 선택한다.
|
||||
- 출력 형식, 오프라인/네트워크 전달 구성, 직접 배포/Store 배포 대상을 분리한다. 로컬 빌드에 Store 계정·자체 서버·EG-BIM 자료를 요구하지 않는다.
|
||||
- EXE 설치 경로·마법사·MSP와 MSIX manifest·OS 설치/업데이트를 분리한다. 미지원 입력을 자동 무시하거나 임의 변환하지 않는다.
|
||||
- EG-BIM 전환·데이터 보존·서버 배포 요구는 적용 트랙에 유지한다. 범용 제품과 적용 완료의 증빙/마일스톤을 구별한다.
|
||||
|
||||
## 반영 위치
|
||||
|
||||
| 대상 | 반영 |
|
||||
| --- | --- |
|
||||
| [범용 출력 계약](../code-design/11-generic-exe-msix-architecture.md) | 책임 경계·두 백엔드·형식별 기능·서명/업데이트·부분 실패·완료 기준 |
|
||||
| [v2 모델](../code-design/02-project-model.md), [예제](../code-design/examples/generic.package-project.json) | 공통 필드 + formats + targets; 기존 EG-BIM v1 입력은 명시적 가져오기 |
|
||||
| 구조·파일·identity·릴리스·패치·UI·검증 문서 | 공통 규칙과 EXE 전용 규칙 분리, MSIX 연결 |
|
||||
| [배포 계획](../plan/README.md), [Store](../plan/05-microsoft-store.md), [검토](../plan/09-plan-review.md) | 패키지 생성과 등록 분리, 적용 사례 범위 명시 |
|
||||
| [백로그](../backlog/README.md) | 기존 ID 유지, BL-46~53 필수 추가; 총 53개. 공통과 EG-BIM/서버/Store 게이트 분리 |
|
||||
| [일정 v2](../plan/10-development-schedule.md) | 단독·AI 없음 유지, MSIX 8주 잠정 추가, 범용 W38 / 전체 적용 W52 / 완충 W53~56 |
|
||||
|
||||
기존 44주+4주 계획과 MSIX 제외 문구는 일정 v2로 대체한다. [앞선 UI 변경 기록](2026-10-19-installer-ui-redesign.md)의 일정 유지 판단은 당시 범위에 대한 이력이며 이번 정정 이후의 기준선이 아니다. UI 시안은 EG-BIM EXE용 참고 테마로 보존한다.
|
||||
|
||||
## 확인과 남은 작업
|
||||
|
||||
문서 링크·JSON 구문·백로그 ID/의존성·일정 날짜의 정합성을 확인한다. 예제에는 실제 payload·서명·identity 확정이 필요한 값이 있으며 실행 가능한 구현으로 표시하지 않는다. WiX/MakeAppx 빌드, 서명, Windows 설치 시험, Store 제출은 이번 문서 변경에서 수행하지 않는다. Gitea 이슈는 생성하지 않는다.
|
||||
@@ -0,0 +1,23 @@
|
||||
# 설치 과정·UI 재설계 변경 기록
|
||||
|
||||
- 요청: InstallShield와 Inno Setup을 참고해 설치 과정과 UI 재디자인.
|
||||
- 변경일: 2026-10-19.
|
||||
- 상태: 설계 및 상호작용 시안 작성. 운영 구현·설치 검증 미완료.
|
||||
- 기준 문서: [재설계](../code-design/10-installer-wizard-redesign.md).
|
||||
- 비교 자료: [이전 시안](../../output/egbim-installer-preview.html), [새 시안](../../output/egbim-installer-wizard-preview.html).
|
||||
|
||||
## 변경 내용
|
||||
|
||||
기존 4단계 시안을 시작·약관/선택·최종 확인·준비·적용·완료 구조로 세분화했다. 신규 설치/전환/패치/복구/제거를 구분하고 이전/다음/취소의 동작을 통일했다. 백업 실패·실행 앱·상태 불명확·재부팅 필요 화면과 제거 확인을 추가했다. 제작기의 페이지 목록/미리보기/속성 패널 구성도 문서로 구체화했다.
|
||||
|
||||
## 영향과 완료 판정
|
||||
|
||||
BL-15, BL-24, BL-30~33의 상세 완료 기준을 갱신한다. 기존 백로그 ID와 미착수 상태를 유지한다. 실행기/패치 계약은 BL-27과 연결한다. 이번 요청은 Gitea 이슈 생성이나 설치 엔진 교체 요청이 아니며 문서만으로 관리한다.
|
||||
|
||||
44주+완충 4주 일정은 기준선을 유지하되 기존 범위 내 상세화라고 해서 추가 공수가 없다고 단정하지 않는다. 모드별 화면과 실패 경로의 구현·시험량을 M0와 M4 착수 시 재산정한다. 사용자 정의 BA 필요성을 기본 테마만으로 해결했다고 표시하지 않는다. AI가 없는 단독 개발 산정 조건은 유지한다.
|
||||
|
||||
## 확인 범위
|
||||
|
||||
공식 자료의 UI 패턴을 확인했고 JavaScript 문법 및 9개 상태 전이 검사를 통과했다. 검사에는 5개 모드의 정상 경로, 약관/경로/제거 확인, 백업 실패, 실행 앱 차단, 적용 실패/취소, 재부팅, 취소 확인 중 전이 차단, 저장 상태 검증을 포함한다. Chromium 렌더링으로 밝은/어두운 테마, 320px 너비, 최종 확인과 백업 실패 화면도 확인했다. 문서 상대 링크와 Git 공백 검사도 통과했다.
|
||||
|
||||
실제 Burn/Tauri 실행, Windows UAC, 백업/복원, MSI/MSP 적용과 접근성 보조기기 시험은 후속 백로그다. 시안의 예시 상태를 실제 설치 검증 증빙으로 사용하지 않는다.
|
||||
@@ -0,0 +1,28 @@
|
||||
# MSIX 제작기 우선 개발
|
||||
|
||||
날짜: 2026-10-19. 사용자 요청에 따라 제품 1차 범위를 MSIX 제작으로 변경했다. 개발자 1명·AI 지원 없음의 산정 조건, 문서 백로그만 관리하는 방침을 유지한다.
|
||||
|
||||
## 결정
|
||||
|
||||
- 1차: 범용 MSIX 프로젝트·파일/manifest·MakeAppx·서명·불변 결과·직접 배포/App Installer·GUI/CLI·실제 설치/업데이트 검증.
|
||||
- 후속: EXE/MSI/MSP/Burn, HTML 설치 마법사, 추가 동작 핸들러, 기존 제품 전환, 자체 그룹 배포 서버, Store 제출 프로필/등록, bundle.
|
||||
- MSIX-only 프로젝트에 MSI GUID·EXE 설정·WiX 도구·Store 계정을 요구하지 않는다.
|
||||
- 시안 대상은 설치 최종 사용자 화면이 아니라 **패키지를 만드는 데스크톱 프로그램**이다. 프로젝트 작업실/단계별 제작 두 외형은 검토 대안이며 둘 다 구현하는 공수를 자동 추가하지 않는다.
|
||||
|
||||
## 반영
|
||||
|
||||
[12번 설계](../code-design/12-msix-first-builder.md), [백로그](../backlog/README.md), [일정 v3](../plan/10-development-schedule.md), 주요 문서의 적용 범위와 색인, [MSIX-only 예제](../code-design/examples/msix.package-project.json), [시안](../../output/msix-builder-preview.html)에 반영한다.
|
||||
|
||||
기존 BL-01~53은 유지한다. 1차 18개/후속 35개로 구분하고 BL-02/03/06/10/16/29/46~53의 인수 기준과 의존성을 현재 범위에 맞게 수정한다. 범용 서명/저장 기능은 BL-50에서 먼저 만들고 EXE 관련 BL-19/20에서 확장한다. BL-53은 두 독립 제품의 **MSIX** 회귀로 변경한다. 이 변경이 EXE 구현 완료를 의미하지 않는다.
|
||||
|
||||
기존 v2의 W38 범용 제작기·W52 전체 적용 일정은 현행 기준이 아니다. v3는 MSIX 24주+완충 4주의 잠정 계획이며 후속 EXE/서버/Store 작업은 일정 미배정이다. 목표 출시일은 사용자 확정 사항이 아니고 MS0에서 도구/서명/지원 범위 실험 후 재산정한다.
|
||||
|
||||
## 이번 변경의 검증
|
||||
|
||||
문서 29개의 로컬 링크, JSON 구문, 53개 작업 ID와 비순환 의존성, 1차 18개 작업에서 후속 작업으로의 의존성 없음, MS0~MS6 및 완충 날짜를 확인했다. `git diff --check`를 통과했다.
|
||||
|
||||
Chrome에서 시안의 메타데이터 반영, 잘못된 버전, 파일 추가/실행 파일 누락, Publisher 불일치/오류 이동, 업데이트 URI, 모의 빌드/로그, 미서명 결과, 설정 변경 후 결과 무효화, 반응형 너비, 실제 시안 전환과 단계 이동을 포함한 11개 검사 묶음을 통과했다. 런타임 페이지 오류는 없었고 밝은/어두운 화면과 좁은 화면을 렌더링해 확인했다. 상태 저장 이벤트가 검증 오류를 지우던 문제는 수정 후 재검증했다.
|
||||
|
||||
이 검증은 문서와 시안에 대한 것이다. Rust 컴파일·MakeAppx 실행·서명·MSIX 설치·업데이트·Store 제출은 수행하지 않았다.
|
||||
|
||||
[앞선 범용 범위 정정](2026-10-19-general-package-builder.md)은 두 형식을 장기 제품 범위로 다룬 이력이다. 현재 첫 제품 완료에는 EXE를 요구하지 않는다. 이전 시안과 설계는 후속 작업 자료로 보존한다. 구현 작업은 모두 미착수이며 이번 결과는 설계와 모의 UI다.
|
||||
@@ -1,5 +1,9 @@
|
||||
# Rust + Tauri 구조와 모듈
|
||||
|
||||
2026-10-19 실행 범위 변경: 첫 구현은 MsixBackend만 제공하며 WixBackend/Burn 연결은 후속이다. WiX 도구를 설치하지 않은 환경에서도 MSIX 제작이 가능해야 한다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
공통 엔진은 제품과 출력 형식에 독립적이다. EG-BIM·Baron·Grimi.exe를 코드에 고정하지 않는다. [범용 출력 계약](11-generic-exe-msix-architecture.md)에 따라 EXE와 MSIX 백엔드를 모두 제공한다.
|
||||
|
||||
## 실행 구조
|
||||
|
||||
```mermaid
|
||||
@@ -9,7 +13,9 @@ flowchart TD
|
||||
CLI[CI용 CLI] --> APP
|
||||
APP --> DOMAIN[프로젝트 검증 · 파일 해석 · 버전/패치 정책]
|
||||
APP --> ADAPTER[도구와 저장소 어댑터]
|
||||
ADAPTER --> WIX[WiX · Burn]
|
||||
ADAPTER --> BACKEND[PackageBackend · 출력별 capability 검사]
|
||||
BACKEND --> WIX[EXE: WiX · Burn]
|
||||
BACKEND --> MSIX[MSIX: Manifest · MakeAppx]
|
||||
ADAPTER --> SIGN[SignTool · 서명 공급자]
|
||||
ADAPTER --> STORE[작업 디렉터리 · 불변 릴리스 저장소]
|
||||
APP --> REPORT[진행 이벤트 · 검증 보고서]
|
||||
@@ -32,7 +38,8 @@ crates/
|
||||
package-domain/ # 타입과 순수 검증/비교 규칙
|
||||
package-engine/ # 작업 흐름, 취소, 상태, 포트 정의
|
||||
package-infra/ # 파일 I/O, WiX, 서명, Windows 프로세스
|
||||
templates/wix/ # 버전 관리되는 설치 정의 템플릿
|
||||
templates/wix/ # EXE/MSI 설치 정의 템플릿
|
||||
templates/msix/ # AppxManifest·자산 매핑 템플릿
|
||||
schemas/ # 프로젝트/매니페스트/IPC JSON Schema
|
||||
tests/fixtures/ # 작은 가상 제품과 기준 MSI 정의
|
||||
docs/
|
||||
@@ -51,6 +58,8 @@ docs/
|
||||
| InstallFlowCompiler | 단계 의존성과 설치 모드 검증, MSI/Burn 실행 정의로 변환 |
|
||||
| InstallerUiCompiler | UI 템플릿·리소스·바인딩 검증, 백엔드 기능 지원 검사 |
|
||||
| BuildCoordinator | 작업 잠금, 단계 실행, 체크포인트, 취소, 실패 기록 |
|
||||
| PackageBackend | format별 capabilities/validate/plan/build/inspect; 제품별 상수 없는 출력 계약 |
|
||||
| MsixBackend | manifest·자산·의존성 검사, MakeAppx 실행, 패키지 identity 추출 |
|
||||
| WixBackend | 설치 정의 생성, MSI/MSP/Burn 빌드, 결과 메타데이터 추출 |
|
||||
| Signer | 서명 정책 적용, 타임스탬프, 실제 서명 검증 결과 반환 |
|
||||
| ArtifactRepository | 기준 릴리스 조회, 콘텐츠 검증, 불변 결과 등록 |
|
||||
@@ -58,7 +67,7 @@ docs/
|
||||
|
||||
포트는 외부 도구를 가짜 구현으로 바꿀 수 있게 한다. 실제 Rust trait의 비동기 형태는 구현 시 확정하되, 모든 작업은 `BuildContext`, 취소 토큰, 타입이 지정된 요청과 결과를 받는다. 도구 종료 코드만 성공 기준으로 삼지 않는다.
|
||||
|
||||
후보 라이브러리는 `serde/serde_json`, `uuid`, `sha2`, `quick-xml`, `tokio`, `clap`, `tracing`이다. 도입 시 유지보수 상태·라이선스·Windows 지원을 확인하고 버전을 고정한다. WiX CLI와 확장, Windows SDK SignTool도 정확한 버전·파일 해시를 `toolchain.lock.json`에 기록한다. WiX 세대가 다른 명령 구문을 혼용하지 않는다.
|
||||
후보 라이브러리는 `serde/serde_json`, `uuid`, `sha2`, `quick-xml`, `tokio`, `clap`, `tracing`이다. 도입 시 유지보수 상태·라이선스·Windows 지원을 확인하고 버전을 고정한다. WiX CLI와 확장, Windows SDK MakeAppx·SignTool도 정확한 버전·파일 해시를 `toolchain.lock.json`에 기록한다. WiX 세대가 다른 명령 구문을 혼용하지 않는다.
|
||||
|
||||
## 작업 수명과 장애 복구
|
||||
|
||||
@@ -70,7 +79,7 @@ GUI 종료 시 실행 중 작업을 안내하고 취소를 요청할 수 있다.
|
||||
|
||||
## 권한 경계
|
||||
|
||||
생성기는 일반 사용자 권한으로 동작한다. 대상 HKLM 레지스트리를 편집하는 것은 생성된 설치기의 역할이다. 빌드 중 사용자 PC에 MSI/MSP를 설치하지 않는다.
|
||||
생성기는 일반 사용자 권한으로 동작한다. 대상 HKLM 레지스트리를 편집하는 것은 생성된 설치기의 역할이다. 빌드 중 사용자 PC에 MSI/MSP/MSIX를 설치하지 않는다. 설치 검증은 별도 VM에서 수행한다.
|
||||
|
||||
웹 UI에는 임의 셸 실행·임의 파일 쓰기 API를 노출하지 않는다. Rust가 허용한 프로젝트와 소스 루트 안에서 요청을 검증한다. 외부 도구는 절대 경로와 인자 배열로 실행하며 `.bat`, `cmd /c`, PowerShell 문자열 조합을 허용하지 않는다. Windows Job Object로 자식 프로세스 수명을 관리하고 실패·취소 시 남은 프로세스를 정리한다. [Rust Command](https://doc.rust-lang.org/std/process/struct.Command.html)
|
||||
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
# 프로젝트와 데이터 모델
|
||||
|
||||
2026-10-19 실행 범위 변경: JSON 스키마 버전은 v2를 유지한다. 첫 구현은 formats.msix와 direct 대상만 활성화하고 formats.exe는 생략 가능하다. v1 EXE 가져오기·Store 출력은 후속이며 미지원 입력을 명시적으로 거부한다. 현재 예제는 [msix.package-project.json](examples/msix.package-project.json)이다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
**현재 계약은 v2다.** [범용 출력 계약](11-generic-exe-msix-architecture.md)의 `formats`와 `targets`를 사용한다. 아래 MSI 컴포넌트·RegistryEntry·PatchRecord는 EXE 백엔드 전용 타입이며 MSIX 프로젝트의 필수 필드가 아니다.
|
||||
|
||||
[범용 v2 예제](examples/generic.package-project.json)는 두 형식을 요청하는 설계 초안이다. null인 UpgradeCode·Publisher·서명 참조, 실제 payload·로고·런타임을 확정하기 전 빌드할 수 없다. 최소 OS와 템플릿 이름도 예시이며 구현된 JSON Schema는 아직 없다. 아래 EG-BIM 예제는 이전 v1 입력으로 보존하고 백업 후 명시적으로 가져온다.
|
||||
|
||||
## 설정과 결과를 분리하는 파일 구조
|
||||
|
||||
2026-10-26 확정: 기본 확장자는 `.isproj`이며 내용은 UTF-8 JSON v2를 유지한다. 열기·저장·기존 JSON 거부와 로컬 파일 이름은 [프로젝트 파일 형식](13-isproj-project-format.md)을 따른다. 기본 파일명과 저장소에 적용했다.
|
||||
|
||||
```text
|
||||
project/
|
||||
package-project.json # 사람이 편집하는 제품/패키지 설정
|
||||
package-project.local.json # PC별 소스 경로, 도구/서명 프로필 참조
|
||||
EG-BIM.isproj # 사람이 편집하는 제품/패키지 설정 (JSON v2)
|
||||
EG-BIM.isproj.local.json # PC별 소스 경로, 도구/서명 프로필 참조
|
||||
identity.lock.json # 제품 계열 및 컴포넌트 식별자 이력
|
||||
toolchain.lock.json # 승인한 도구/템플릿 버전
|
||||
.work/jobs/<jobId>/ # 스냅샷, 스테이징, 생성 WXS, 로그
|
||||
.work/jobs/<jobId>/ # 스냅샷, 대상별 스테이징, WXS/manifest, 로그
|
||||
releases/<releaseId>/
|
||||
release.json # 확정된 메타데이터
|
||||
input.snapshot.json # 설정과 도구, 소스 정보
|
||||
files.resolved.json # 실제 파일 목록, 원본/서명 후 해시
|
||||
identity.snapshot.json
|
||||
artifacts/ # 배포 가능한 파일
|
||||
baseline/ # MSI, wixpdb, signed payload, 설치 정의
|
||||
baseline/ # 대상별 입력·서명 payload; EXE는 MSI/wixpdb/설치 정의, MSIX는 manifest/identity
|
||||
reports/ # 정적 검사와 빌드 당시 검증
|
||||
patches/<patchId>/ # 기준→목표 패치와 동일 종류의 기록
|
||||
attestations/<artifactDigest>/ # 이후 VM 시험 결과; 아티팩트는 수정 안 함
|
||||
@@ -27,14 +35,14 @@ project/
|
||||
|
||||
| 타입 | 핵심 필드와 규칙 |
|
||||
| --- | --- |
|
||||
| PackageProject | schemaVersion, projectId, product, sources, files, registry, outputs, prerequisites, signing, patchPolicy, installationFlow, installerUi |
|
||||
| PackageProject v2 | schemaVersion, product, sources, files, formats, targets; 형식별 입력 분리. 별도 프로젝트 ID 없음 |
|
||||
| InstallationFlow / InstallerUi | 단계 의존성·모드·조건, 테마/페이지/바인딩. [상세 계약](09-install-flow-and-ui.md) 참조 |
|
||||
| ProductSpec | productId, displayName, manufacturer, architecture, language, installScope, version, engineVersion, upgradeCode, installRoot |
|
||||
| FileRule | 고유 id, source alias, include/exclude 패턴, destinationDirectory, required |
|
||||
| ResolvedFile | source-relative path, target-relative path, 크기, SHA-256, PE 정보, componentId/Guid, signingPolicy |
|
||||
| ProductSpec | displayName, manufacturer, displayVersion; 제품별 선택 메타데이터. 설치 범위·GUID는 formats.exe, MSIX identity는 formats.msix |
|
||||
| FileRule | 고유 id, source alias, include/exclude 패턴, targetRelativePath, required; v1 destinationDirectory는 형식별 루트와 상대 경로로 변환 |
|
||||
| ResolvedFile | source-relative path, target-relative path, 크기, SHA-256, PE 정보, signingPolicy; EXE 전용 확장에 componentId/Guid |
|
||||
| RegistryEntry | id, hive, view, key, name, typed value, component, 설치/제거 정책 |
|
||||
| IdentityLock | 제품 계열, ProductCode, 컴포넌트 GUID/키 경로, 삭제된 식별자 tombstone |
|
||||
| ReleaseRecord | releaseId, buildId, 설정 해시, 소스 커밋(선택), 실제 MSI/Burn 식별자, artifacts, 호환성, 서명/도구 정보 |
|
||||
| IdentityLock | 형식별 계열. EXE: ProductCode·컴포넌트 GUID·tombstone; MSIX: Name·Publisher·Architecture·버전 이력 |
|
||||
| ReleaseRecord | releaseId, buildId, 설정 해시, 소스 커밋(선택), targets별 실제 MSI/Burn 또는 MSIX identity, artifacts, 호환성, 서명/도구 정보 |
|
||||
| PatchRecord | patchId/PatchCode, 기준 상태, 목표 releaseId, family/sequence, 필요한 원본·패치, 전체 대체 경로 |
|
||||
| Artifact | artifactId, kind, 상대 경로, u64 크기, 최종 SHA-256, dependsOn, 서명 결과 |
|
||||
| ValidationReport | reportId, 대상 해시, 검사 항목, pass/fail/notRun, 환경, 도구 버전 |
|
||||
@@ -49,7 +57,7 @@ project/
|
||||
|
||||
버전·GUID 문자열 형식, 참조 id 존재 여부, 중복 대상 경로, 필수 파일 누락, hive와 설치 범위의 모순은 Rust에서 검사한다. 출력 경로는 소스 루트 밖이어야 한다. 검증 결과는 `severity`, `code`, `fieldPath`, `message`, `remediation`으로 반환하여 화면에서 해당 설정으로 이동하게 한다.
|
||||
|
||||
`release.json`은 고정된 프로젝트 설정을 복사하는 것으로 끝내지 않는다. 빌드된 MSI·MSP·EXE에서 읽은 실제 제품 코드·버전과 파일 정보를 기록하고 기대값과 대조한다. 메타데이터 자신의 해시를 자기 안에 넣지 않는다. 메타데이터 서명을 사용할 경우 별도 서명 파일을 생성한다.
|
||||
`release.json`은 고정된 프로젝트 설정을 복사하는 것으로 끝내지 않는다. 빌드된 MSI·MSP·EXE·MSIX에서 읽은 실제 제품 코드·버전과 파일 정보를 기록하고 기대값과 대조한다. 메타데이터 자신의 해시를 자기 안에 넣지 않는다. 메타데이터 서명을 사용할 경우 별도 서명 파일을 생성한다.
|
||||
|
||||
## 편집·빌드 동시성
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 파일 목록, 설치 위치와 레지스트리
|
||||
|
||||
2026-10-19 실행 범위 변경: 공통 파일 해석만 1차에 구현한다. 아래 MSI 컴포넌트·레지스트리 컴파일은 후속이다. MSIX는 패키지 상대 경로와 지원 선언을 검증한다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
아래 APPDIR·설치 경로·MSI 컴포넌트·레지스트리 작성 규칙은 EXE 백엔드 계약이다. 공통 파일 수집은 MSIX에도 재사용하되 MSIX는 패키지 상대 경로와 지원 manifest 선언으로 매핑한다. 임의 HKLM 쓰기·사용자 지정 설치 폴더는 자동 변환하지 않는다. 패키지 파일과 쓰기 가능한 앱 데이터를 분리한다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
## 파일 목록 편집과 해석
|
||||
|
||||
파일/폴더 추가, 상대 경로 유지, 포함/제외 패턴, 필수 파일 지정, 대상 폴더 변경을 지원한다. 화면에는 최종 배포 경로, 크기, PE 여부, 서명 상태, 직전 릴리스 대비 추가·수정·삭제를 표시한다. 패턴만 저장하되 빌드마다 확장한 실제 목록도 보존한다.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 버전과 GUID 관리
|
||||
|
||||
2026-10-19 실행 범위 변경: 1차는 MSIX identity와 4부분 버전 이력이다. 아래 MSI GUID·MSP 규칙은 후속 EXE 계약이다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
아래 MSI 3부분 버전·GUID·MSP 계열은 EXE 백엔드 계약이다. MSIX는 Name/Publisher/Architecture와 4부분 Version을 별도 관리하고 Store 대상 추가 규칙을 검증한다. 제품 표시 버전에서 두 형식으로의 매핑은 명시적으로 설정한다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
## 서로 다른 버전의 구분
|
||||
|
||||
| 값 | 목적 |
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# 전체 릴리스 생성 파이프라인
|
||||
|
||||
## 작업 단계와 상태
|
||||
2026-10-19 실행 범위 변경: 1차 실행 경로는 MSIX manifest→MakeAppx→서명/검증→불변 결과이며 EXE/CAB/MSP와 Store 프로필은 후속이다. 미서명 개발 결과와 직접 배포 준비 결과를 구분한다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
**공통 조정기 + 형식별 빌드**로 구성한다. 아래 단계 표의 WiX·MSI·Burn·CAB·PE 용량 제한은 EXE 경로다. MSIX는 `manifest/자산 생성 → MakeAppx pack → 실제 identity/내용 검사 → 대상별 서명/검증 → 불변 저장`으로 분기한다. MSIX 결과에는 manifest·SDK 정보·패키지·서명/검증 보고서를 보존한다. Store 제출용 결과와 직접 설치 가능한 결과를 구별한다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
공통 상태는 대상별로 기록한다. 요청한 EXE/MSIX 중 하나라도 실패하면 전체 작업은 `PartialFailed`이며 성공한 결과를 덮어쓰지 않는다. `Finalized`, 직접 배포 준비, `StoreSubmissionReady`, 실제 Store 승인/공개는 다른 판정이다. `DeploymentReady`는 선택한 배포 대상의 설치 증빙을 요구하며 EG-BIM 전환 증빙을 다른 제품에 강제하지 않는다.
|
||||
|
||||
## 공통 작업 단계와 상태
|
||||
|
||||
```text
|
||||
Draft → Planned → Running → Built → ArtifactVerified → Finalized
|
||||
@@ -29,13 +35,13 @@ Finalized + 별도 설치 시험 증빙 → DeploymentReady
|
||||
|
||||
디스크 여유는 원본 스테이징, 서명 복사본, 압축 전후 파일, 임시 파일, 기준 버전과 최종 결과를 포함해 계산한다. 정확히 예측할 수 없는 부분은 보수적인 여유량을 적용한다. 수 GB 파일을 메모리에 통째로 적재하지 않고 스트림으로 복사·해시한다.
|
||||
|
||||
## 대용량 출력 프로필
|
||||
## EXE 출력 프로필과 대용량 지원
|
||||
|
||||
| 프로필 | 산출물과 정책 |
|
||||
| --- | --- |
|
||||
| offline-layout | Setup.exe + EG-BIM.msi + Data*.cab + prerequisites. 인터넷 없이 설치 가능한 전체 폴더 |
|
||||
| offline-layout | Setup.exe + Product.msi + Data*.cab + prerequisites. 인터넷 없이 설치 가능한 전체 폴더 |
|
||||
| network | WebSetup.exe + 원격 MSI/CAB/런타임. 모든 payload에 불변 URL·해시·크기 연결 |
|
||||
| store-singlefile | 필수 요소를 포함한 단일 오프라인 EXE 또는 적합한 MSI. 크기·서명·Store 검증 실패 시 생성 불가 |
|
||||
| offline-singlefile | 필수 요소를 포함한 단일 오프라인 EXE. 직접 배포에도 사용하며 크기·서명 검증 필수 |
|
||||
|
||||
총 설치 용량이 2GB를 넘는 경우 외부 CAB를 분할한다. 기본 압축 전 CAB 예산은 **512MiB 제안값**이며 파일별 크기와 실제 생성 CAB를 검사한다. 이것은 Windows Installer의 고정 제한값이 아니다. WiX MediaTemplate의 미디어 분할 설정과 단일 대형 파일 처리 설정은 서로 다르다. 도구 버전별 지원을 검증하여 매핑한다. [WiX MediaTemplate](https://docs.firegiant.com/wix/schema/wxs/mediatemplate/)
|
||||
|
||||
@@ -43,7 +49,7 @@ Finalized + 별도 설치 시험 증빙 → DeploymentReady
|
||||
|
||||
서명할 PE 파일은 4GB 이상에서 서명 문제가 있으므로 단일 EXE에 모든 내용을 무조건 포함하지 않는다. 4GB 미만도 선택한 Burn 버전·컨테이너·압축 방식에서 성공한다는 보장은 없어 실제 빌드와 서명 검증으로 판정한다. [Microsoft 대형 파일 서명 문제](https://learn.microsoft.com/en-us/windows/msix/package/signing-known-issues)
|
||||
|
||||
Store의 MSI/EXE 제출은 독립 실행 가능한 오프라인 설치 패키지를 요구한다. 네트워크 stub이나 별도 CAB URL 목록이 단일 제출 파일을 대신한다고 가정하지 않는다. `store-singlefile`이 성립하지 않으면 Store 준비 상태를 실패로 보고하고 MSIX/제품 분할 등 별도 경로를 검토한다. [Store 패키지 요건](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msi/app-package-requirements)
|
||||
Store의 MSI/EXE 제출은 독립 실행 가능한 오프라인 설치 패키지를 요구한다. 네트워크 stub이나 별도 CAB URL 목록이 단일 제출 파일을 대신한다고 가정하지 않는다. `format=exe, delivery=offline-singlefile, distribution=store`가 성립하지 않으면 해당 대상의 Store 준비 상태를 실패로 보고한다. MSIX 출력은 별도 필수 백엔드이며 해당 제품의 적합성 없이 자동 전환하지 않는다. [Store 패키지 요건](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msi/app-package-requirements)
|
||||
|
||||
## 서명 정책
|
||||
|
||||
@@ -55,14 +61,14 @@ Rust/WiX는 서명 인증서를 발급하지 않는다. `Signer` 어댑터가 Si
|
||||
|
||||
인증서 체인·정책·타임스탬프를 검증하고 서명자, 검증 환경, 검증 시각을 기록한다. 일시적인 서명 서비스 오류는 제한적으로 재시도하되 완료된 파일을 재서명하여 해시를 바꾸지 않는다. 토큰·PIN·개인 키·전체 인증 응답은 로그에 남기지 않는다.
|
||||
|
||||
## 전체 설치와 Minor Upgrade
|
||||
## EXE/MSI 전체 설치와 Minor Upgrade
|
||||
|
||||
목표 릴리스마다 신규 설치 가능한 전체 MSI를 만든다. 같은 ProductCode를 유지하는 minor upgrade를 기존 설치에 적용하는 것은 단순히 새 MSI를 실행하는 것과 다르므로 별도의 `upgradeRoute`를 제공한다. MVP에서는 해당 기준에 MSP를 적용하는 경로를 우선한다.
|
||||
EXE/MSI 대상의 목표 릴리스마다 신규 설치 가능한 전체 MSI를 만든다. 같은 ProductCode를 유지하는 minor upgrade를 기존 설치에 적용하는 것은 단순히 새 MSI를 실행하는 것과 다르므로 별도의 `upgradeRoute`를 제공한다. MVP에서는 해당 기준에 MSP를 적용하는 경로를 우선한다.
|
||||
|
||||
MSP가 없는 상태에서 전체 MSI를 대체 업데이트로 사용하려면 해당 버전에 맞는 reinstall/업데이트 동작과 Burn 탐지를 검증한다. 미검증 시 `fallbackArtifactId`만 넣어 실행 가능하다고 표시하지 않고 `FullUpgradeRouteUnavailable`로 차단한다. major upgrade 대상과 minor upgrade 대상의 실행 계획을 분리한다.
|
||||
|
||||
## 확정·내보내기
|
||||
|
||||
동일 releaseId의 출력 폴더가 있으면 덮어쓰지 않는다. 확정 전 실패한 폴더는 격리하고 명시적인 정리 작업으로 제거한다. 기본 보존 대상은 최종 MSI/CAB/EXE, 서명된 실제 payload, wixpdb, 생성 WXS, 잠금/스냅샷, 로그와 검증 보고서다. 지원 중인 패치가 참조하는 기준은 자동 정리에서 제외한다.
|
||||
동일 releaseId의 출력 폴더가 있으면 덮어쓰지 않는다. 확정 전 실패한 폴더는 격리하고 명시적인 정리 작업으로 제거한다. EXE 기본 보존 대상은 최종 MSI/CAB/EXE, 서명된 실제 payload, wixpdb, 생성 WXS, 잠금/스냅샷, 로그와 검증 보고서다. 지원 중인 패치가 참조하는 기준은 자동 정리에서 제외한다.
|
||||
|
||||
배포 내보내기는 artifacts와 의존 관계, 최종 SHA-256, 설치/업그레이드 경로, 지원 OS·런타임, 패치 기준을 매니페스트로 만든다. offline-layout의 전체 설치 대체 경로는 단일 MSI가 아니라 필요한 CAB·런타임까지 포함한 artifact graph를 가리킨다. 업로드 URL에는 releaseId를 포함한다. payload URL 계획은 Burn 생성 전에 고정하고, 그룹 공개는 별도 배포 시스템에서 수행한다.
|
||||
@@ -1,5 +1,9 @@
|
||||
# 기준 버전별 패치 생성
|
||||
|
||||
2026-10-19 실행 범위 변경: 아래 MSP 파이프라인은 후속 EXE 범위로 이월한다. 1차 MSIX는 전체 상위 버전 패키지와 App Installer 업데이트를 제공한다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
이 문서는 EXE/MSI 백엔드의 MSP 생성 계약이다. MSIX 업데이트는 버전 증가 패키지와 Windows 배포 기능을 사용하며 MSP·Burn 기준 상태를 적용하지 않는다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
## 입력 계약
|
||||
|
||||
패치는 이전 릴리스의 폴더와 새 폴더만 비교해 만드는 ZIP이 아니다. 보존한 기준 MSI/빌드 정보와 목표 전체 릴리스를 사용해 WiX MSP를 생성한다. WiX는 기준·업데이트 입력으로 MSI 또는 wixpdb와 관련 payload를 사용한다. 정확한 도구 호출은 버전별 백엔드가 담당한다. [WiX Windows Installer patches](https://docs.firegiant.com/wix/tools/patches/)
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
# Tauri 화면과 명령 인터페이스
|
||||
|
||||
2026-10-19 실행 범위 변경: 1차 화면은 앱 정보·파일 구성·패키지 설정·서명·업데이트·검증/빌드다. EXE/Store 선택·과정/마법사 편집·MSP는 첫 UI에 노출하지 않는다. 아래 확장 화면/명령은 후속 계약이다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
## 형식별 제작 화면과 CLI
|
||||
|
||||
공통 제품/파일 설정 다음에 **출력 대상**을 편집한다. 각 대상은 `format`, `delivery`, `distribution`을 별도 선택한다. EXE 탭은 설치 경로·레지스트리·과정/마법사·MSP를, MSIX 탭은 identity·manifest·앱 자산·의존성·capabilities·업데이트를 편집한다. MSIX 설치 경로는 OS 관리로 안내한다. Store 설정은 해당 대상을 선택한 경우에만 요구한다.
|
||||
|
||||
CLI의 validate/plan/build/export는 `--target <targetId>` 또는 `--all-targets`를 받도록 확장한다. CLI와 GUI가 같은 capability 검사를 사용한다. 모든 대상 요청 중 하나만 성공하면 전체 성공 코드를 반환하지 않고 대상별 결과와 `PartialFailed`를 반환한다. patch 명령은 EXE/MSI 대상 전용이며 MSIX에는 버전 증가 빌드를 안내한다. [v2 출력 계약](11-generic-exe-msix-architecture.md)이 아래 기존 EXE 중심 화면에 우선한다.
|
||||
|
||||
|
||||
## 화면 구성
|
||||
|
||||
프로젝트 생성·열기·저장은 `.isproj`만 지원한다. 시작 화면의 두 버튼과 파일 다이얼로그, 최근 목록, CLI 모두 [프로젝트 파일 형식 계약](13-isproj-project-format.md)을 따른다. 기존 `.json` 프로젝트 호환·변환은 제공하지 않는다.
|
||||
|
||||
| 화면 | 입력/행동 | 결과 |
|
||||
| --- | --- | --- |
|
||||
| 프로젝트 | 생성·열기·저장, 제품명/제조사/엔진, 소스 alias 연결 | 현재 revision, 미확정 필드 |
|
||||
@@ -53,8 +64,8 @@
|
||||
다음은 구현 예정인 명령 형식이다. 현재 실행 가능한 명령이 아니다.
|
||||
|
||||
```powershell
|
||||
package-builder validate --project .\package-project.json --format json
|
||||
package-builder plan release --project .\package-project.json --profile offline-layout
|
||||
package-builder validate --project .\EG-BIM.isproj --format json
|
||||
package-builder plan release --project .\EG-BIM.isproj --profile offline-layout
|
||||
package-builder build --plan-id <planId>
|
||||
package-builder plan patch --target <releaseId> --base-state <baseStateId>
|
||||
package-builder job status --id <jobId> --format json
|
||||
@@ -67,4 +78,4 @@ CI용 `release`/`patch` 편의 명령은 같은 엔진에서 plan+build를 연
|
||||
|
||||
## 생성 프로그램 자체 배포
|
||||
|
||||
Tauri 앱 자체의 설치 패키지와 버전은 EG-BIM의 프로젝트/제품 GUID와 분리한다. 개발 머신의 WebView2, WiX, SDK 및 서명 연동 도구를 검사하는 환경 진단 화면을 제공한다. 필요한 외부 도구를 자동 다운로드하거나 번들에 재배포하는 기능은 라이선스·고정 버전 검토 후 추가하며, 최초 구현은 관리자가 준비한 도구 프로필을 사용한다.
|
||||
Tauri 앱 자체의 설치 패키지·버전·identity는 각 고객 제품의 EXE/MSIX identity와 분리한다. 개발 머신의 WebView2, WiX, SDK 및 서명 연동 도구를 검사하는 환경 진단 화면을 제공한다. 필요한 외부 도구를 자동 다운로드하거나 번들에 재배포하는 기능은 라이선스·고정 버전 검토 후 추가하며, 최초 구현은 관리자가 준비한 도구 프로필을 사용한다.
|
||||
@@ -1,15 +1,24 @@
|
||||
# 검증 계획과 구현 순서
|
||||
|
||||
2026-10-19 실행 범위 변경: 현재 출시 게이트는 두 독립 제품의 **MSIX** 생성·서명·설치·업데이트·제거다. 아래 두 형식 통합/EXE/EG-BIM 게이트는 후속으로 이월한다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
## 후속 두 형식 통합 게이트
|
||||
|
||||
후속 두 형식 완성 시에는 EXE와 MSIX를 모두 검증한다. 첫 MSIX 출시에는 아래 EXE 검증을 요구하지 않는다. 최소 두 독립 가상 제품에서 두 형식의 생성·서명/검증·신규 설치·실행·업데이트·제거와 데이터 보존을 VM으로 검증한다. MSIX는 Publisher/인증서 불일치, 누락 자산·런타임, OS 조건, 임의 설치 경로·미지원 기능, 업데이트 실패를 추가 시험한다. EXE/MSIX 동시 요청의 부분 실패와 대상별 불변 결과도 검사한다. Store 계정과 EG-BIM·자체 서버 없이 이 게이트를 통과할 수 있어야 한다.
|
||||
|
||||
제품명·경로·레지스트리·게시자를 서로 다른 값으로 시험해 하드코딩을 탐지한다. EG-BIM 실제 전환·CAD 업무 회귀와 자체 서버 승격은 별도 적용 게이트다. Store 제출 준비 검사와 심사 승인도 분리한다. [상세 계약](11-generic-exe-msix-architecture.md), [BL-46~53](../backlog/README.md) 참조.
|
||||
|
||||
|
||||
## 자동 검증
|
||||
|
||||
| 계층 | 검증할 핵심 동작 |
|
||||
| --- | --- |
|
||||
| 도메인 | MSI 버전 경계, GUID 수명, component 이동/삭제 판정, 지원 기준 상태 비교 |
|
||||
| 도메인 | 공통 출력 대상/capability; EXE의 MSI 버전·GUID·기준 상태; MSIX identity·4부분 버전·배포 대상 조건 |
|
||||
| 프로젝트 계약 | JSON Schema와 Rust 역직렬화 일치, 알 수 없는 필드, 마이그레이션, revision 충돌 |
|
||||
| 파일 해석 | 포함/제외, 필수 파일 누락, 대소문자 충돌, 경로 탈출/reparse point, 원본 무변경 |
|
||||
| 레지스트리 | 타입 범위, 32/64비트, XML/MSI 문자열 escaping, 지원하지 않는 HKCU 정책 차단 |
|
||||
| 작업 엔진 | 가짜 WiX/Signer를 통한 단계 실패, 취소, 중복 요청, 체크포인트, 잠금 충돌 |
|
||||
| 실제 도구 통합 | 작은 샘플 제품으로 MSI/EXE/MSP 생성, 실제 식별자와 서명/해시 추출 |
|
||||
| 작업 엔진 | 가짜 WixBackend/MsixBackend/Signer를 통한 단계 실패, 취소, 중복 요청, 체크포인트, 잠금 충돌 |
|
||||
| 실제 도구 통합 | 작은 독립 제품들로 MSI/EXE/MSP/MSIX 생성, 실제 식별자와 서명/해시 추출 |
|
||||
| 대용량 | 총 2GB 초과와 여러 CAB, 크기 합산 오버플로, 메모리 사용, 개별 제한 초과 실패 |
|
||||
| UI/IPC | 계획 이후 설정 변경 차단, 권한 없는 Command, 입력/로그의 HTML 실행 방지 |
|
||||
| 설치 과정/UI | 의존 단계 삭제·순환·조건 오류 차단, 대화형/무인 결과 일치, patch/repair Feature 유지, CustomAction 복구, WebView2 없는 PC |
|
||||
@@ -22,7 +31,8 @@ CAB 시험에는 압축이 매우 잘 되는 0바이트 반복 데이터만 쓰
|
||||
|
||||
| 시나리오 | 합격 조건 |
|
||||
| --- | --- |
|
||||
| 신규 설치 | 기본/사용자 지정 경로, 파일·레지스트리·런타임·실행 정상 |
|
||||
| EXE 신규 설치 | 기본/사용자 지정 경로, 파일·레지스트리·런타임·실행 정상 |
|
||||
| MSIX 신규 설치/업데이트 | OS 관리 경로·앱 실행·의존성·서명 신뢰 확인, 버전 증가 업데이트·제거·데이터 보존 |
|
||||
| 기존 InstallShield 전환 | 실제 배포본별 탐지, 설정·CUI·도면 보존, 기존 삭제 스크립트 영향 확인 |
|
||||
| 오프라인 전체 설치 | 네트워크 차단 상태에서 CAB와 런타임을 모두 로컬로 해석 |
|
||||
| 네트워크 설치 | 단절·재시도·캐시·해시 불일치 처리, 불완전 다운로드 미적용 |
|
||||
@@ -31,28 +41,32 @@ CAB 시험에는 압축이 매우 잘 되는 0바이트 반복 데이터만 쓰
|
||||
| 파일 버전/수정 | 동일 PE 버전의 변경 파일, 수정된 비버전 파일, 누락 파일의 결과 검증 |
|
||||
| 실패/재부팅 | 앱 실행 중, 파일 잠김, 디스크 부족, 3010/1641, rollback와 복구 판정 |
|
||||
| 설치 후 유지보수 | Burn 표시와 MSI 상태, repair, uninstall, 다음 패치·전체 업그레이드 |
|
||||
| Store 출력 | 단일 파일, 무다운로드, silent 경로, 서명, 버전별 고정 URL 조건 |
|
||||
| Store EXE 출력 | 단일 파일, 무다운로드, silent 경로, 서명, 버전별 고정 URL 조건 |
|
||||
| Store MSIX 출력 | 제출 identity/버전/manifest·자산·지원 선언 검증. 제출 파일과 직접 설치용 서명본 구분; 실제 심사는 별도 |
|
||||
|
||||
사용자 데이터 보존은 해시가 반드시 동일해야 하는 공급자 파일과 별도 판정한다. 저장된 백업이 있다는 것만으로 복구 성공이라고 하지 않고 실제 복원과 앱 재실행까지 확인한다.
|
||||
|
||||
## 구현 순서
|
||||
|
||||
아래 표는 영역별 구현 설명이다. 실제 작업 배치는 [통합 백로그](../backlog/README.md)와 [단독 개발 일정](../plan/10-development-schedule.md)을 따른다. 기존 제거 및 Rust/Burn 연결 실험은 초기에 수행하고, 실제 EG-BIM 전환 구현은 GUI 완성보다 앞에 배치한다.
|
||||
|
||||
| 단계 | 구현 내용 | 완료 기준 |
|
||||
| --- | --- | --- |
|
||||
| 1. 기준 확정 | 실제 배포 payload, ISM 대조, 런타임, 출시본 GUID, 도구 버전 | 출처가 기록된 첫 프로젝트와 전환 위험 목록 |
|
||||
| 1. 기준 확정 | 두 가상 제품, EXE/MSIX 도구·범위·서명, EG-BIM 자료는 별도 조사 | 범용 빌드 계약과 적용 전환 위험을 각각 기록 |
|
||||
| 2. Rust 엔진/CLI | 스키마, 파일 해석, identity lock, 검증/계획 | fixture에서 안정적인 목록·GUID와 설명 가능한 오류 |
|
||||
| 3. 전체 릴리스 | WXS 생성, MSI/Burn, 분할 CAB, 서명 어댑터 | 작은 제품과 2GB 초과 제품의 전체 설치 시험 통과 |
|
||||
| 4. 버전별 패치 | 기준 저장소, diff, 호환성, MSP, 순서/이력 | 최소 두 기준 상태에서 동일 목표 도달·repair·제거 통과 |
|
||||
| 5. Tauri UI | 프로젝트/파일/레지스트리/릴리스/패치/작업 화면 | CLI와 같은 계획·결과, 긴 작업 중 UI 응답 유지 |
|
||||
| 필수 MSIX. 패키지 출력 | manifest·SDK·서명·업데이트·제작 화면 | 독립 제품 두 개의 두 형식 시험과 부분 실패 검사 통과 |
|
||||
| 6. EG-BIM 전환 | 실제 파일/레지스트리/백업, 기존 업데이터 연계 | 실제 IS 출시본→WiX→후속 MSP 경로 시험 통과 |
|
||||
| 7. 배포 연결 | 내보내기, 외부 증빙, 업로드 계약, Store 가능성 | 불변 파일과 기준 정보가 배포 시스템에 연결 |
|
||||
|
||||
버전별 패치는 필수 범위이며 최초 제품 완성에서 제외하지 않는다. 다만 작은 시험 제품으로 엔진을 검증한 뒤 실제 EG-BIM 데이터를 적용한다. UI 작업은 엔진 계약이 안정화된 후 병행할 수 있다.
|
||||
EXE/MSI 버전별 MSP와 MSIX 버전별 업데이트는 필수 범위이며 최초 제품 완성에서 제외하지 않는다. 다만 작은 시험 제품으로 엔진을 검증한 뒤 실제 EG-BIM 데이터를 적용한다. UI 작업은 엔진 계약이 안정화된 후 순차 수행한다. 단독 개발자의 병렬 작업 용량을 가정하지 않는다.
|
||||
|
||||
설치 과정/화면 편집 요구는 [09 설계](09-install-flow-and-ui.md)를 따른다. 단계 2~3에 과정 검증과 기본 테마 출력을, 단계 5에 과정/UI 편집기를 추가한다. 자유로운 페이지/분기 지원은 Rust/Burn 연결 실험 후 사용자 정의 BA로 구현하며 기본 테마 편집만으로 해당 요구를 완료 처리하지 않는다.
|
||||
|
||||
## 정식 배포를 막는 미확정 사항
|
||||
|
||||
실제 설치용 소스 폴더, 제조사 표시명, 런타임 목록, 서명 프로필, 기존 설치본 목록과 파괴적 제거 동작, 업데이터의 MSI/MSP 실행 계약, Burn과 패치의 유지보수 동작은 아직 확정되지 않았다. 초안 설정으로 편집·차이 계산·개발 패키지 검증을 진행할 수 있지만 정식 릴리스의 배포 준비 상태는 부여하지 않는다.
|
||||
각 제품의 실제 소스·표시명·런타임·서명과 선택 형식의 identity를 확정해야 해당 제품의 정식 배포 준비를 판정할 수 있다. EXE는 Burn/MSP 유지보수, MSIX는 manifest·서명·업데이트 증빙을 요구한다. EG-BIM의 기존 설치본·파괴적 제거·NuGet 계약 미확정은 EG-BIM 전환을 차단하며 다른 제품의 빌드를 막지 않는다. 초안 예제만으로 정식 릴리스 준비를 선언하지 않는다.
|
||||
|
||||
이 문서 작성 단계에서는 설계 문서의 경로·예제 JSON·문서 간 일관성만 검사한다. Rust 컴파일, WiX 빌드, 실제 서명, 설치·패치·Store 심사는 수행하지 않았다.
|
||||
이 문서 작성 단계에서는 설계 문서의 경로·예제 JSON·문서 간 일관성만 검사한다. Rust 컴파일, WiX/MakeAppx 빌드, 실제 서명, 설치·패치·Store 심사는 수행하지 않았다.
|
||||
@@ -1,7 +1,13 @@
|
||||
# 설치 과정 편집과 설치 UI 커스터마이징
|
||||
|
||||
2026-10-19 실행 범위 변경: 이 문서의 EXE 설치 과정·BA·HTML 페이지 편집은 후속 범위다. 첫 제품의 Tauri UI는 MSIX 제작 설정을 편집하며 설치 마법사를 생성하지 않는다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
이 문서의 최종 사용자 설치 과정·마법사·Burn BA 커스터마이징은 **EXE 출력 전용**이다. MSIX는 Windows/Store가 설치 UI와 경로를 관리하며 제작기는 manifest의 이름·아이콘·지원 선언을 편집한다. 두 형식의 설정을 혼합하거나 미지원 단계를 조용히 생략하지 않는다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
## 목표
|
||||
|
||||
2026-10-19에 InstallShield와 Inno Setup의 마법사 패턴을 참고해 [설치 과정·UI를 재설계](10-installer-wizard-redesign.md)했다. 아래 실행/데이터 계약을 유지하면서 페이지 흐름, 편집 화면과 실패·취소·재부팅 상태를 구체화한다.
|
||||
|
||||
패키지 제작자가 설치 단계를 추가·삭제·비활성화·재배치하고, 최종 사용자가 보는 설치 화면도 변경할 수 있게 한다. 제작자가 정하는 실행 정책과 설치 사용자가 선택하는 옵션은 구분한다.
|
||||
|
||||
- **설치 과정 편집기**: 환경 검사, 런타임, 제품 설치, 설정 이전, 바로가기, 완료 후 실행 등 작업을 설정한다.
|
||||
@@ -93,7 +99,7 @@ UI는 일반 권한을 유지하고 시스템 변경은 Burn/MSI의 적합한
|
||||
|
||||
## 데이터 계약과 무인 설치
|
||||
|
||||
`PackageProject`에 `installationFlow`와 `installerUi`를 추가한다. 기존 초안 예제에서 생략한 경우 버전이 고정된 기본 과정/테마를 적용하고 빌드 스냅샷에는 전체 정의와 리소스 해시를 저장한다.
|
||||
v2 `PackageProject.formats.exe`에 `installationFlow`와 `installerUi`를 둔다. 기존 초안 예제에서 생략한 경우 버전이 고정된 기본 과정/테마를 적용하고 빌드 스냅샷에는 전체 정의와 리소스 해시를 저장한다.
|
||||
|
||||
| 정의 | 필드 |
|
||||
| --- | --- |
|
||||
@@ -110,7 +116,9 @@ Feature 선택은 MSI 모델에 연결하고 repair/patch에서 설치된 선택
|
||||
|
||||
## 검증과 구현 순서
|
||||
|
||||
단계 카탈로그·검증 → 과정 편집기 → 기본 테마 편집 → Rust/Burn 연결 실험 → 사용자 정의 BA·페이지 편집 순서로 구현한다. 모두 기존 전체 릴리스·MSP와 같은 스냅샷·서명·검증 절차를 적용한다.
|
||||
최소 Rust/Burn 연결·부트스트랩 실험 → 단계 카탈로그·검증 → 과정 편집기 → 기본 테마 편집 → 사용자 정의 BA·페이지 편집 순서로 진행한다. 모두 기존 전체 릴리스·MSP와 같은 스냅샷·서명·검증 절차를 적용한다.
|
||||
|
||||
2026-10-19의 [통합 일정](../plan/10-development-schedule.md)에 따라 위험 실험(BL-08)은 기준 확정 단계에 수행한다. 본 편집기와 사용자 정의 BA 구현은 공통 엔진 및 적용 계약 검증 이후 진행한다.
|
||||
|
||||
- 의존 단계 삭제, 순환, 모드/조건 오류의 사전 검출.
|
||||
- 대화형·숨김·무인 모드에서 관리 파일/레지스트리 결과의 동등성.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# 설치 마법사와 편집 UI 재설계
|
||||
|
||||
2026-10-19 실행 범위 변경: 이 시안은 후속 EXE 출력용 자료로 보존한다. 이번 첫 제품 시안은 MSIX 제작 프로그램 화면이다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
아래 EG-BIM 시안은 **범용 제작기의 EXE 출력용 참고 테마**다. 제품명·로고·경로·문구는 프로젝트에서 교체한다. MSIX의 OS 설치 UI를 이 마법사로 대체하지 않으며 MSIX 제작 화면은 별도 manifest/출력 설정을 제공한다. [범용 출력 계약](11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
변경일: 2026-10-19. InstallShield와 Inno Setup의 마법사 패턴을 참고해 EG-BIM의 설치 과정과 화면을 구체화한다. 패키지 엔진은 기존 WiX MSI/MSP + Burn 설계를 유지한다. 설치기 제품을 바꾸거나 기존 제거 동작을 그대로 복제하는 변경이 아니다.
|
||||
|
||||
현재 결과는 상호작용 시안과 구현 설계다. 실제 설치·백업·서명 검사·관리자 승격·재부팅은 실행하지 않으며 표시되는 경로·진행률·검증 결과는 예시다.
|
||||
|
||||
## 참고한 패턴
|
||||
|
||||
| 출처 | 확인한 특징 | EG-BIM에 적용한 설계 |
|
||||
| --- | --- | --- |
|
||||
| [InstallShield: 기본 패키지와 의존 패키지](https://docs.revenera.com/installshield31helplib/helplibrary/StePrimDepend.htm) | 설치된 기본 패키지 상태에 따라 최초 설치와 유지 관리 모드를 구분한다. | 제품 탐지를 먼저 하고 신규 설치·전환·패치·복구·제거를 분리한다. 런타임 존재만으로 제품 설치 여부를 판정하지 않는다. |
|
||||
| [InstallShield: Wizard Pages 편집](https://www.revenera.com/blog/software-installation/putting-the-wizard-in-wizard-pages/) | 페이지 생성·복제·템플릿으로 화면을 구성하는 편집 패턴을 설명한다. 오래된 버전의 설명이므로 내부 XML 형식은 재사용하지 않는다. | 제작기를 페이지 목록·미리보기·속성 패널로 구성한다. 페이지와 동작 연결은 자체 계약으로 검증한다. |
|
||||
| [Inno Setup: WizardStyle](https://jrsoftware.org/ishelp/topic_setup_wizardstyle.htm) | classic/modern의 화면 표현과 테마 설정을 제공한다. | 간결한 제목/설명, 본문, 일관된 하단 버튼을 갖는 마법사형을 제공한다. 지원 여부는 선택한 WiX/BA 백엔드에서 별도 판정한다. |
|
||||
| [Inno Setup: 사용자 정의 페이지](https://jrsoftware.org/ishelp/topic_scriptpages.htm) | 기존 페이지 사이에 사용자 정의 입력 페이지를 삽입하고 입력값을 읽을 수 있다. | 페이지 ID와 조건·입력 바인딩을 가진 페이지 카탈로그를 둔다. 자유 페이지는 사용자 정의 BA에서 처리한다. |
|
||||
| [Inno Setup: Tasks](https://jrsoftware.org/ishelp/topic_taskssection.htm) | 추가 작업을 체크박스/라디오 버튼으로 표현하고 실제 설치 항목에 연결한다. | 바로가기 같은 사용자 선택 작업을 필수 구성요소와 구분한다. 선택 UI만 있고 실제 작업 연결이 없는 설정을 검증 오류로 처리한다. |
|
||||
| [Inno Setup: CloseApplications](https://jrsoftware.org/ishelp/topic_setup_closeapplications.htm) | 설치 준비 단계에서 사용 중인 파일과 앱 종료를 다루며 강제 종료 시 작업 손실 위험을 설명한다. | 저장·종료 안내와 재확인 상태를 제공한다. EG-BIM의 미저장 도면을 강제 종료하는 기본 동작은 채택하지 않는다. |
|
||||
|
||||
위 자료는 2026-10-19 확인했다. 제품별 외형·동작에서 참고한 패턴이며, 두 도구의 모든 기능이 WiX 기본 테마에 그대로 매핑된다는 의미는 아니다.
|
||||
|
||||
## 디자인 방향
|
||||
|
||||
두 외형은 동일한 페이지 데이터와 실행 계약을 사용한다. 기본 제안은 **진행 안내형**이다. 기존 설치본 전환의 준비·백업·적용 단계를 쉽게 이해하도록 현재 구간을 왼쪽에 표시한다. **표준 마법사형**은 Inno Setup 계열에서 익숙한 상단 제목/설명·중앙 본문·하단 버튼 구조로 화면을 간결하게 구성한다.
|
||||
|
||||
- 제목은 현재 할 일을 설명하고 본문에는 해당 단계에 필요한 입력만 둔다.
|
||||
- 하단 버튼은 `이전 / 다음 또는 작업 시작 / 취소`, 완료 시 `마침`으로 일관되게 배치한다.
|
||||
- 단계 목록은 진행 표시이며 클릭으로 필수 단계를 건너뛰는 탐색 메뉴가 아니다.
|
||||
- 신규 설치의 위치·구성요소·바로가기 선택은 한 화면의 세 구역으로 묶는다. 설정이 많아지면 위치/구성/추가 작업 페이지로 나누되 같은 변수를 사용한다.
|
||||
- 기존 설치본의 경로와 패치/복구의 Feature 상태는 읽기 전용이다. 제거에서는 제거 대상과 유지할 데이터를 분리해서 표시한다.
|
||||
- 재부팅 필요, 백업 실패, 설치 실패, 취소는 각각 별도 상태로 표시한다. 실패를 완료 체크 표시로 표현하지 않는다.
|
||||
- 운영 화면에는 MSI GUID·도구 버전·개발 백엔드 이름을 노출하지 않는다. 진단 정보는 상세 로그에 둔다.
|
||||
|
||||
[상호작용 시안 원본](../../output/egbim-installer-wizard.html), [브라우저 미리보기](../../output/egbim-installer-wizard-preview.html). 이전 [초기 시안](../../output/egbim-installer-preview.html)은 비교 자료로 보존한다.
|
||||
|
||||
## 상황별 화면 흐름
|
||||
|
||||
실제 모드는 탐지 결과와 승인된 적용 경로에서 결정한다. 시안 위의 상황/상태 선택기는 검토용이며 배포되는 설치기의 메뉴가 아니다.
|
||||
|
||||
| 모드 | 사용자 화면 | 핵심 제한 |
|
||||
| --- | --- | --- |
|
||||
| 신규 설치 | 시작 → 약관 → 위치/구성/바로가기 → 최종 확인 → 준비 → 적용 → 완료/재부팅 | 약관 미동의·경로 오류를 차단. 필수 본체는 해제 불가. |
|
||||
| 기존 InstallShield 전환 | 기존 제품 탐지 → 최종 확인 → 준비/파일 확보/백업 → 전환/복원 → 완료/재부팅 | 지원 legacy만 허용. 기존 경로 유지. 백업 검증 전에 제거 금지. |
|
||||
| 후속 MSP | 기준/목표 확인 → 최종 확인 → 준비/백업 → 패치/설정 확인 → 완료/재부팅 | Feature·경로 유지. 기준 상태 불일치 시 검증된 대체 경로 안내 또는 차단. |
|
||||
| 설치 복구 | 복구 안내 → 최종 확인 → 원본 확보/준비 → 복구 → 완료/재부팅 | 새 WiX 설치 체계의 지원 상태만 대상. 필요한 원본 미확보 시 적용 차단. |
|
||||
| 제거 | 제거 안내 → 대상/보존 데이터 확인 및 동의 → 준비 → 제거 → 완료/재부팅 | 사용자 도면·설정·백업과 타사 CAD 소유 연결은 유지. 공유 런타임 일괄 제거 금지. |
|
||||
|
||||
약관 버전이 달라진 업데이트에는 약관 단계를 추가한다. 시안의 전환·패치 경로는 재동의가 필요 없는 예시이며, 실제 생략 조건은 기존 동의 버전·배포 약관 정책으로 판정한다. 무인 설치는 별도 명시적 동의 입력 계약을 사용한다. 화면을 숨긴 것만으로 동의했다고 간주하지 않는다.
|
||||
|
||||
복구·제거 화면의 데이터 보존 정책은 새 설치기에 적용할 설계다. 기존 InstallShield 제거 스크립트에 자동으로 적용된다고 보장하지 않는다. legacy 제거는 전환 핸들러와 검증된 백업 절차를 통해서만 실행한다. 일반적인 구성 변경(Modify)은 Feature 변경 경로가 검증될 때 별도 모드로 확장하고 이번 시안에는 노출하지 않는다.
|
||||
|
||||
## 페이지별 계약
|
||||
|
||||
| 페이지 ID | 표시/입력 | 다음 단계 조건 | 사용자 버튼 |
|
||||
| --- | --- | --- | --- |
|
||||
| welcome | 제품/작업·탐지된 설치 위치·보존 정책 | 지원 가능한 제품/버전/모드, 차단 오류 없음 | 다음, 취소 |
|
||||
| license | 승인된 약관 전문/버전·동의 | 해당 약관 동의 | 이전, 다음, 취소 |
|
||||
| options | 설치 위치, 필수/선택 Feature, 바로가기 | 경로/권한/지원 Feature 검증 | 이전, 다음, 취소 |
|
||||
| review | 실제 실행 계획, 경로, 구성, 백업/보존, 필요한 권한 | 유효한 planId/revision, 제거 시 명시적 확인 | 이전, 설치/업데이트/복구/제거 시작, 취소 |
|
||||
| prepare | 실행 앱, 패키지 확보·서명·해시·디스크·백업 결과 | 모든 필수 준비 성공, 앱 종료, 적용 직전 허가 유효 | 취소, 차단 원인별 다시 확인 |
|
||||
| apply | 현재 작업/전체 상태, 엔진이 제공한 진행률, 로그 | 엔진 완료·오류·취소·재부팅 이벤트 | 가능한 지점에서 취소 요청; 이전 없음 |
|
||||
| finish | 설치 결과, 복원 상태, 백업 위치·실행 선택 | 성공이며 재부팅 불필요 | 마침 |
|
||||
| rebootRequired | 재부팅 필요 이유, 지금/나중에 선택 | 사용자의 명시적 선택; 기본은 나중에 | 마침 또는 재시작 |
|
||||
| failure | 실패 단계, 기존 제품 상태, 백업/로그, 다음 조치 | 복구 상태에 따라 다름 | 재검사 또는 진단 안내/닫기 |
|
||||
| cancelled | 변경 전 취소 여부 또는 적용 후 복구 결과 | 엔진이 확인한 실제 상태 | 닫기 |
|
||||
|
||||
`prepare`에는 다운로드·캐시 확보와 로컬 무결성 검사를 포함한다. 온라인 흐름에서는 적용 허가를 재확인하고, 오프라인 흐름은 승인된 배포 정책을 적용한다. `review`의 시작 버튼 이후에는 입력값을 고정하고 작업 ID 하나로 실행한다. 준비 실패 후 입력 수정이 필요하면 계획을 다시 만든다.
|
||||
|
||||
## 실패·취소·완료 동작
|
||||
|
||||
| 상태 | 표현과 허용 동작 |
|
||||
| --- | --- |
|
||||
| 실행 앱 발견 | 저장/종료 안내 → 다시 확인. 자동 강제 종료와 사용자 작업 저장 추정 금지. |
|
||||
| 다운로드/공간/백업 실패 | 실제 원인을 표시. 제거 전이라면 기존 제품 미변경을 표시하고 안전한 준비 단계만 재시도. |
|
||||
| 적용 전 취소 | 확인 후 종료. 만들어진 백업/캐시의 보존 정책은 명시하고 기존 제품은 유지. |
|
||||
| 적용 중 취소 | 취소 요청 접수와 처리 중 상태를 표시. 프로세스를 강제 종료하거나 즉시 성공으로 표시하지 않는다. |
|
||||
| 적용 실패 또는 취소 후 상태 불명확 | 로그·백업 보존, 복구 진단 안내. 무조건 다시 설치/전체 설치 버튼을 제공하지 않는다. |
|
||||
| 롤백 완료 확인 | MSI 복구와 외부 런타임/설정 보상 결과를 구분. 각 결과가 확인된 범위만 복구 완료로 표시. |
|
||||
| 재부팅 필요 | ‘설치 성공·실행 확인 대기’를 구분. 앱 실행 선택 숨김, 지금 재부팅은 기본 미선택. 실제 재부팅은 명시적 동의 후 수행. |
|
||||
| 정상 완료 | 호환 설정 복원과 실제 확인 항목 표시. 앱 실행은 대화형·원래 사용자 권한. 백업 자동 삭제 금지. |
|
||||
|
||||
시안의 ‘작업 진행’ 버튼은 자동 설치 이벤트를 수동으로 넘겨보는 검토용 조작이다. 실제 UI의 prepare/apply에는 이 버튼이 없으며 Burn/작업 서비스 이벤트로 진행한다. ‘다시 확인’과 ‘다시 검사’도 시안에서는 정상 상태로 바꾸는 모의 동작이며 실제 파일/프로세스를 검사하지 않는다.
|
||||
|
||||
## 제작기의 설치 과정·UI 편집 화면
|
||||
|
||||
화면 편집은 **왼쪽 페이지 목록 / 중앙 미리보기 / 오른쪽 속성**의 세 영역으로 구성한다. 설치 과정 탭에서는 같은 공간을 **작업 목록 / 모드별 실행 순서 / 조건·입력·복구 정책**으로 바꾼다. 최종 사용자 마법사의 단계 이동과 제작자의 페이지 편집은 구분한다.
|
||||
|
||||
| 영역 | 편집 동작 | 제약과 피드백 |
|
||||
| --- | --- | --- |
|
||||
| 상단 설정 | install/upgrade/patch/repair/uninstall 미리보기, 기본 테마/사용자 정의 BA 선택 | 선택 백엔드가 지원하지 않는 기능 표시. 모드 변경은 화면 미리보기이며 시스템 실행 아님. |
|
||||
| 페이지 목록 | 템플릿에서 추가, 선택, 복제, 허용 순서 변경, 표시 조건 | review/prepare/apply/결과의 실행 계약은 잠금. 페이지 숨김으로 필수 작업을 삭제하지 않음. |
|
||||
| 중앙 미리보기 | 선택 페이지와 이전/다음 연결, 정상/차단/실패/재부팅 상태 | 실제 설치 미수행. native 출력 시험 필요 표시. |
|
||||
| 속성 패널 | 제목/설명/번역 키, 로고/이미지, 지원 색상/글꼴, 레이아웃 슬롯, 입력 변수와 검증 | 읽기 전용 설치 경로/필수 Feature 등 모드 제약을 즉시 표시. 임의 JS/셸 바인딩 불가. |
|
||||
| 설치 과정 | 카탈로그 추가, 선택 단계 활성화, 의존성 범위 내 순서, 실패 정책 확인 | 필수 백업/무결성/설치 작업 제거 차단. trusted catalog의 권한/복구 정책은 임의 약화 불가. |
|
||||
| 검증 결과 | 페이지·단계·변수 경로와 오류 원인/수정 위치 | 미지원 기능·순환·필수 입력 누락이면 배포 빌드 불가. |
|
||||
|
||||
설치 과정 편집기 자체의 세 영역 UI는 이 문서에서 구체화했으며 이번 상호작용 파일은 **배포되는 설치 마법사**의 화면을 구현한 시안이다. 제작기 편집 화면의 구현 완료를 의미하지 않는다.
|
||||
|
||||
## 커스터마이징 데이터와 백엔드 지원
|
||||
|
||||
기존 `InstallerUi`의 templateId/version·assets·strings/locales·pages·bindings를 유지한다. 레이아웃·색상 등 지원 속성은 버전이 지정된 템플릿 스키마에서 정의한다. `InstallationFlow`는 별도로 유지하며 각 화면이 직접 관리자 작업을 실행하지 않는다.
|
||||
|
||||
| 변경 | 기본 테마 | 사용자 정의 BA |
|
||||
| --- | --- | --- |
|
||||
| 로고·문구·약관·지원 스타일 | 고정 WiX 테마가 지원하는 속성으로 매핑 | 구현한 토큰/리소스 스키마로 지원 |
|
||||
| 시안의 두 외형 전체 재현 | 페이지/컨트롤 계약에 대한 실험 필요, 동일 재현 보장 안 함 | 선택한 컴포넌트/레이아웃 구현 후 지원 |
|
||||
| 임의 페이지·입력·분기 | 미지원이면 빌드 차단 | 페이지 그래프·입력 검증·무인 기본값 계약 필요 |
|
||||
| 필수 백업/무결성 약화 | 불가 | 불가 |
|
||||
| UAC 화면 변경 | 불가 | 불가 |
|
||||
|
||||
UI 수정은 새 스냅샷·빌드·서명·시험으로 배포한다. 목표 페이지 목록, 약관 버전, 입력 검증, 모드 분기, 선택 Feature가 달라지면 설치/패치 호환성도 다시 검사한다.
|
||||
|
||||
## 인수 기준과 작업 연결
|
||||
|
||||
- BL-15/30: 페이지와 실행 단계의 구분, 필수 단계 보호, 모드별 과정 검증.
|
||||
- BL-24/27: 준비/적용/취소/실패/재부팅 상태와 승인된 설치·패치·복구 경로 연결.
|
||||
- BL-31: 두 외형의 템플릿·문구·리소스 편집과 백엔드 지원 여부 표시.
|
||||
- BL-32: 약관 조건·입력·페이지 분기·선택값 유지·설치 시작 후 계획 고정.
|
||||
- BL-33: 5개 모드, 약관/경로/제거 확인, 이전 이동 시 선택값 보존, 준비 실패, 실행 앱, 적용 중 취소, 상태 불명확, 재부팅을 시험. DPI·키보드·스크린 리더·다국어 및 native 결과를 검증.
|
||||
|
||||
시안 작성은 위 구현 항목을 완료 처리하지 않는다. 신규 기능 ID를 늘리지 않고 미착수 BL-15/24/30~33의 완료 기준을 구체화한다. 일정은 단독 개발·AI 지원 없음 가정을 유지하며 M0/BL-08 실험과 M4 착수 시 기본 테마로 가능한 화면 범위와 사용자 정의 BA 공수를 다시 산정한다.
|
||||
@@ -0,0 +1,95 @@
|
||||
# 범용 설치 패키지 제작과 EXE·MSIX 출력
|
||||
|
||||
2026-10-19 실행 범위 변경: 이 문서의 “두 형식 모두 필수”는 장기 확장 구조다. 최신 사용자 요청에 따라 **MSIX를 먼저 완성하고 EXE는 후속**으로 이월한다. 두 형식 동시 완성을 첫 출시의 조건으로 사용하지 않는다. Store 제출 프로필도 후속이다. [현재 설계](12-msix-first-builder.md) 참조.
|
||||
|
||||
결정일: 2026-10-19. 사용자 의도에 따라 제품 범위를 정정한다. 이 문서는 기존 문서의 EG-BIM 전용 가정과 MSIX 후속 검토 분류를 대체한다. 아직 구현·설치 시험을 완료한 것은 아니다.
|
||||
|
||||
## 제품과 배포의 경계
|
||||
|
||||
개발 대상은 **여러 Windows 제품의 설치 프로젝트를 작성하고 EXE 또는 MSIX를 생성하는 범용 제작기**다. 제작기는 두 형식을 모두 필수 지원하며, 각 프로젝트는 EXE만, MSIX만, 두 형식을 함께 선택할 수 있다. EG-BIM은 기존 InstallShield 전환을 검증하는 적용 사례다. 제품명·제조사·경로·실행 파일·레지스트리·런타임·서명자는 프로젝트 입력이며 엔진에 고정하지 않는다.
|
||||
|
||||
Microsoft Store는 생성된 파일을 등록하는 배포 대상이다. Store 계정이나 등록 없이도 EXE와 직접 배포용 MSIX를 만들 수 있어야 한다. Store 심사 통과와 특정 고객의 전환 완료는 범용 제작기의 패키지 생성 성공 조건이 아니다.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
P[제품별 프로젝트와 원본 파일] --> C[Rust 공통 검증·스냅샷·출력 계획]
|
||||
C --> E[EXE 백엔드: WiX MSI + Burn]
|
||||
C --> M[MSIX 백엔드: Manifest + MakeAppx]
|
||||
E --> EA[EXE와 필요한 MSI/CAB/런타임]
|
||||
M --> MA[MSIX]
|
||||
EA --> D[직접 배포·네트워크 배포]
|
||||
MA --> D
|
||||
EA --> S[Store 제출용 내보내기·검사]
|
||||
MA --> S
|
||||
S --> R[별도 Store 등록·심사·공개]
|
||||
```
|
||||
|
||||
| 축 | 설정과 책임 |
|
||||
| --- | --- |
|
||||
| 출력 형식 `format` | `exe` 또는 `msix`; 제작기 필수 지원 |
|
||||
| 전달 구성 `delivery` | EXE: `offline-singlefile`, `offline-layout`, `network`; MSIX: `package`, `appinstaller` |
|
||||
| 배포 대상 `distribution` | `direct` 또는 `store`; 형식을 결정하지 않음 |
|
||||
| 공개 정책 | 자체 서버 그룹 승인, Store 제출/공개 등 별도 운영 시스템의 책임 |
|
||||
|
||||
허용 조합은 EXE 직접 배포의 세 delivery, EXE Store의 `offline-singlefile`, MSIX 직접 배포의 `package/appinstaller`, MSIX Store의 `package`다. Store 대상의 `network`·`offline-layout`·`appinstaller`와 형식에 맞지 않는 조합은 계획 단계에서 차단한다.
|
||||
|
||||
`network`는 제3의 패키지 형식이 아니다. EXE는 원격 payload를 받는 부트스트래퍼, MSIX는 필요할 때 HTTPS 패키지를 참조하는 `.appinstaller`로 전달한다. `.appinstaller`는 설치 패키지 자체가 아닌 배포 설명 파일이다. [Microsoft App Installer 개요](https://learn.microsoft.com/en-us/windows/msix/app-installer/app-installer-file-overview)
|
||||
|
||||
## 백엔드와 최초 지원 범위
|
||||
|
||||
공통 `PackageBackend` 포트는 `capabilities`, `validate`, `plan`, `build`, `inspect` 계약을 제공한다. `WixBackend`와 `MsixBackend`를 주입하고 서명·저장·작업 취소는 공통 서비스가 조정한다. 프로젝트 검증과 실제 출력 검사 모두 백엔드별 규칙을 사용한다. 도구 버전과 해시는 잠금 파일에 고정한다.
|
||||
|
||||
| 기능 | EXE / WiX·Burn | MSIX |
|
||||
| --- | --- | --- |
|
||||
| 설치 위치 | 프로젝트 기본 경로와 허용된 사용자 선택 | OS 관리; 임의 설치 폴더 입력 제공 안 함 |
|
||||
| 최종 사용자 화면 | 표준 테마, 사용자 정의 BA, 설치 단계 편집 | Windows/Store 설치 UI; manifest 표시명·아이콘 등 앱 메타데이터 편집 |
|
||||
| 파일·설정 | 디렉터리·MSI 컴포넌트·명시적 레지스트리 | 패키지 내부 경로·지원 manifest 선언; 임의 HKLM 작업으로 변환하지 않음 |
|
||||
| 런타임 | 번들에 포함하거나 검증된 원격 payload 사용 | 지원 프레임워크 의존성 또는 앱의 자체 포함 구성 검증 |
|
||||
| 업데이트 | MSI 기준 상태별 MSP, 검증된 전체 업그레이드 | 동일 계열의 버전 증가 MSIX; 직접 배포/App Installer 또는 Store |
|
||||
| 기존 설치 전환 | 명시적 탐지·백업·제거·복원 정책 | 별도 전환 계획; 기존 EXE 자동 제거를 가정하지 않음 |
|
||||
|
||||
MSIX 최초 범위는 패키징 가능한 일반 데스크톱 앱의 파일, 실행 항목, 로고, 최소 OS, 의존성, 허용 capability/extension 선언이다. 서비스·드라이버·임의 custom action·복잡한 CAD/COM 연동은 초기 지원 목록 밖으로 두고 지원되지 않는 설정을 빌드 전에 차단한다. 이는 모든 MSIX가 해당 기능을 원천 지원하지 않는다는 뜻이 아니다. 앱별 호환성을 검토하고 검증된 매핑을 추가한다. [MSIX 준비 사항](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-prepare)
|
||||
|
||||
MSIX는 완성된 설치 EXE를 확장자만 바꿔 만드는 결과물이 아니다. 제품 payload와 선언적 설정에서 각 형식을 생성한다. 기존 설치기를 실행해 변경을 캡처하는 자동 변환 기능은 별도 후속 범위다. 한 제품의 EXE 지원이 곧 그 제품의 MSIX 호환성을 의미하지 않는다.
|
||||
|
||||
## 프로젝트 v2 계약
|
||||
|
||||
공통 필드는 `schemaVersion`, `product`, `sources`, `files`, `formats`, `targets`다. 2026-10-27 결정으로 별도 프로젝트 ID를 제거했다. 제품 표시 버전은 공통으로 두되 실제 MSI/MSIX 버전은 형식별로 명시하고 검증한다. [설계용 예제](examples/generic.package-project.json)는 두 형식과 배포 대상을 독립 선택하는 구조를 보여 준다.
|
||||
|
||||
- `formats.exe`: MSI 버전·UpgradeCode·설치 범위·기본 경로, 레지스트리, 런타임, MSP 정책, `installationFlow`, `installerUi`.
|
||||
- `formats.msix`: Identity Name·Publisher·Version·Architecture, 애플리케이션 실행 경로·로고, 최소 OS, 의존성과 capabilities/extensions. MSI GUID나 Burn 페이지를 요구하지 않는다.
|
||||
- `targets[]`: 안정적인 id, format, delivery, distribution, signingProfileRef, 필요 시 불변 payload URL 또는 Store identity 참조. 네트워크 URL·인증서·Store 이름이 미확정이면 해당 대상만 계획에서 차단한다.
|
||||
- `identity.lock.json`: EXE의 MSI/Burn 계열과 MSIX의 패키지 계열을 분리한다. MSIX Publisher 변경을 MSI UpgradeCode 교체로 처리하지 않는다.
|
||||
- `ReleaseRecord.targets[]`: 대상별 실제 식별자·산출물·서명 결과·검증 증빙·상태를 저장한다. MSI/MSP 필드는 해당 형식에만 존재한다.
|
||||
|
||||
v1 EG-BIM 예제는 이전 EXE 전용 설계 입력으로 보존한다. v1→v2 가져오기는 백업과 변경 보고서를 만들고 EXE 필드를 이동한다. MSIX publisher나 Store identity를 임의 생성하지 않으며 사용자 입력 전에는 MSIX 대상을 활성화하지 않는다. `store-singlefile`은 `format=exe`, `delivery=offline-singlefile`, `distribution=store`로 명시적으로 변환한다. 알 수 없는 필드/버전과 손실되는 변환은 오류다.
|
||||
|
||||
제품 릴리스 하나에 EXE·MSIX를 함께 요청하면 출력 계획에 두 대상이 고정된다. 한쪽 실패는 전체 성공으로 표시하지 않는다. 성공한 대상은 개별 보존할 수 있으나 전체 요청은 `PartialFailed`로 기록하고 통합 배포 준비 상태를 부여하지 않는다. 실패 대상 재시도는 새 buildId를 사용하며 이미 확정한 파일을 덮어쓰지 않는다.
|
||||
|
||||
## 생성·서명·내보내기
|
||||
|
||||
공통 검증 → 입력 스냅샷 → 대상별 호환성 검사 → 백엔드 빌드 → 대상 정책에 따른 서명/검증 → 최종 해시·불변 저장 순서다.
|
||||
|
||||
EXE는 기존 MSI/CAB/Burn 생성·서명 파이프라인을 사용한다. MSIX는 파일 매핑과 `AppxManifest.xml` 생성 → SDK manifest/자산 검사 → `MakeAppx pack` → 패키지 내용/identity 검사 → 대상별 서명 → 검증 순서다. MakeAppx의 검증을 우회해 성공 처리하지 않는다. `.msix` 생성이 최초 필수이며 다중 아키텍처 `.msixbundle`은 확장 범위다. MakeAppx만으로 `.msixupload`까지 생성된다고 가정하지 않는다. [MakeAppx 공식 문서](https://learn.microsoft.com/en-us/windows/msix/package/create-app-package-with-makeappx-tool)
|
||||
|
||||
직접 배포 MSIX는 대상 PC가 신뢰할 수 있는 인증서로 서명하고, manifest Publisher와 인증서 Subject 일치를 검증한다. 개발 인증서 결과와 일반 사용자 배포 준비 상태를 구분한다. 개인 키는 패키지에 포함하지 않는다. [MSIX 인증서 요건](https://learn.microsoft.com/en-us/windows/msix/package/create-certificate-package-signing)
|
||||
|
||||
Store MSIX 출력은 Partner Center의 제품 identity에 맞춘 제출용 결과로 관리한다. Store의 배포 서명은 이후 단계이므로 서명되지 않은 제출 파일을 직접 설치 가능으로 표시하지 않는다. 직접 배포용 서명본과 제출용 파일은 대상별 해시로 구별한다. Store는 `.msix` 등의 패키지를 받으며 제출·심사·공개는 제작기 빌드 상태와 별도다. [Store 업로드 형식](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/upload-app-packages)
|
||||
|
||||
Store EXE 출력은 단일 완전 오프라인 설치 파일·무인 인자·서명·고정 HTTPS URL 등 제출 요건을 추가 검증한다. 직접 배포용 `offline-layout`이나 `network` 성공만으로 Store 준비 완료를 선언하지 않는다. [Store EXE 패키지 요건](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msi/app-package-requirements)
|
||||
|
||||
## 버전·업데이트·공존
|
||||
|
||||
MSI의 3부분 버전/GUID/MSP 정책은 EXE 백엔드 전용이다. MSIX는 4부분 숫자 버전을 검증한다. Store 대상은 첫 부분 0 금지와 마지막 부분 0 등 Store 버전 요건도 적용한다. 공통 표시 버전 문자열을 무검증으로 복사하지 않는다. [Store MSIX 버전 규칙](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/app-package-requirements)
|
||||
|
||||
MSIX 업데이트에 MSP를 생성하거나 설치 폴더에 자체 패치를 덮어쓰지 않는다. 버전 증가 패키지를 제공하고 Windows 배포 기능을 이용한다. 직접 배포의 App Installer 설정과 Store 관리 업데이트는 별도 정책이다. 재설치·제거·업데이트 실패와 앱 데이터 보존을 각각 VM에서 확인한다.
|
||||
|
||||
동일 제품의 EXE↔MSIX는 자동 상호 업그레이드가 아니다. 기본은 서로 독립된 설치로 취급하고 공존 허용 여부, 앱 데이터 소유권, 파일 연결, 실행 항목 충돌을 프로젝트에서 결정한다. 전환 기능을 제공하려면 기존 제품 탐지·백업·복원·실패 복구를 별도 검증한다. Publisher/Store identity 차이도 자동 통합하지 않는다.
|
||||
|
||||
## 제작 화면과 완료 기준
|
||||
|
||||
제작기는 공통 제품·파일 화면 뒤에 출력 대상 편집을 제공한다. EXE 탭에서는 설치 경로·레지스트리·과정/마법사·MSP를, MSIX 탭에서는 manifest·앱 자산·identity·capabilities·업데이트 정책을 편집한다. 출력 대상별 미지원 설정을 이유와 필드 위치로 표시하며 조용히 무시하지 않는다. MSIX 선택 화면에 EXE 설치 경로/마법사 편집을 그대로 노출하지 않는다.
|
||||
|
||||
최소 두 개의 독립된 가상 제품으로 이름·게시자·실행 파일·경로가 하드코딩되지 않았음을 검증한다. 각 제품에서 EXE와 MSIX 생성, 직접 설치, 실행, 업데이트, 제거, 데이터 보존을 시험한다. Store 계정·자체 배포 서버 없이 이 시험을 수행할 수 있어야 한다. 잘못된 Publisher·누락 런타임/자산·미지원 기능·한쪽 출력 실패도 검사한다. EG-BIM의 실제 전환과 Store 제출은 별도 적용 증빙으로 관리한다. 계정 없는 공통 시험에서는 가상 Store identity로 제출 규칙과 오류 처리를 검증한다. 실제 Partner Center identity가 확인되지 않은 출력은 `StoreSubmissionReady`로 표시하지 않는다.
|
||||
|
||||
구현은 [BL-46~53](../backlog/README.md), 일정은 [단독 개발 기준선 v2](../plan/10-development-schedule.md), 변경 사유는 [변경 기록](../changes/2026-10-19-general-package-builder.md)을 따른다.
|
||||
@@ -0,0 +1,79 @@
|
||||
# MSIX 우선 제작기 — 첫 버전 설계와 화면
|
||||
|
||||
결정일: 2026-10-19. 사용자의 “우선 MSIX를 만들어주는 프로그램을 개발” 요청에 따른 현재 기준이다. [11번 설계](11-generic-exe-msix-architecture.md)의 범용 구조를 유지하되 두 형식 동시 완성 요구를 **MSIX 먼저, EXE는 후속**으로 변경한다. Rust/Tauri 앱과 실제 패키징 엔진은 아직 구현하지 않았다.
|
||||
|
||||
## 첫 제품의 범위
|
||||
|
||||
2026-10-26 명칭·파일 형식 결정: 정식 프로그램 명칭은 **Installer Studio**, 프로젝트 파일은 **`.isproj` (JSON v2)**만 지원한다. 아래 작업용 이름은 최초 시안의 기록이다. [파일 형식 규칙](13-isproj-project-format.md)이 파일명·열기·저장에 관한 이전 예시에 우선하며 기존 JSON 호환은 제공하지 않는다.
|
||||
|
||||
첫 제품은 Windows 앱의 배포 파일과 메타데이터를 입력받아 직접 배포 가능한 `.msix`를 만드는 **범용 MSIX 제작기**다. 디자인의 `MSIX Studio`는 작업용 이름이다. EG-BIM에 종속되지 않으며 Store 계정이나 자체 배포 서버 구축 없이 패키지를 만들 수 있어야 한다.
|
||||
|
||||
| 1차 필수 | 완료 조건 |
|
||||
| --- | --- |
|
||||
| 제품별 프로젝트 | `.isproj` (JSON v2) 전용 열기/저장, 기존 JSON 미지원, 앱 이름·게시자·버전·파일·실행 항목·자산 설정 |
|
||||
| 입력과 manifest | 파일 포함/제외·경로 충돌·필수 자산·아키텍처·최소 OS·의존성·허용 선언 검증 |
|
||||
| MSIX 생성 | Windows SDK MakeAppx, 결과 내용/identity 확인, 원본 무변경 |
|
||||
| 서명 | 개발/운영/미서명 상태 구별, Publisher와 인증서 Subject 검증, 서명 후 최종 해시 |
|
||||
| 작업/내보내기 | 취소·실패·재시도, 불변 결과·로그·보고서·도구 버전 보존 |
|
||||
| 직접 배포 업데이트 | 선택적으로 `.appinstaller` 생성, HTTPS 경로·버전·업데이트 정책 검사와 VM 시험 |
|
||||
| GUI와 CLI | 같은 검증/빌드 계약, 제품별 파일·패키지·서명·업데이트 화면 |
|
||||
| 검증 | 두 독립 가상 제품의 MSIX 설치·실행·상위 버전 업데이트·제거·데이터 보존 증빙 |
|
||||
|
||||
최초 범위는 단일 앱 실행 항목, 한 대상당 단일 아키텍처의 `.msix`다. 지원 OS/CPU의 정확한 조합은 MS0에서 고정한다. 시안의 x64/ARM64와 Windows 버전은 선택 예시이며 지원 인증 결과가 아니다. 자산 파일·스키마·런타임 의존성은 실제 SDK 및 VM에서 검증한다.
|
||||
|
||||
후속 범위는 EXE/MSI/MSP/Burn, HTML 설치 마법사/사용자 정의 BA, 설치 과정 핸들러, EG-BIM legacy 전환, 자체 인증/그룹 배포 서버, Store 제출용 프로필·계정 연결·등록, MSIX bundle, 기존 설치기 캡처/자동 변환이다. 기존 작업은 삭제하지 않고 이월한다. **MSIX 제작기 v1 완료에 EXE 생성이나 두 형식 동시 회귀를 요구하지 않는다.**
|
||||
|
||||
## 구조와 생성 계약
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
UI[Tauri 제작 화면] --> E[Rust 공통 엔진]
|
||||
CLI[CLI] --> E
|
||||
E --> V[프로젝트·파일·manifest 검사]
|
||||
V --> B[MsixBackend / MakeAppx]
|
||||
B --> S[서명·패키지 검증]
|
||||
S --> R[불변 MSIX·보고서·선택 App Installer]
|
||||
```
|
||||
|
||||
`PackageBackend` 추상화는 유지하되 첫 구현은 `MsixBackend`만 제공한다. WixBackend 구현·WiX 설치·MSI GUID 발급은 첫 제품의 의존성이 아니다. v2 모델에서 `formats.exe`는 생략 가능하며 MSIX-only 프로젝트에 EXE 설정을 요구하지 않는다. 기존 EXE/v1 프로젝트는 지원 불가 사유와 후속 가져오기 안내를 표시하고 조용히 변환하지 않는다. [MSIX-only 예제](examples/msix.package-project.json)는 미확정 설계 입력이다.
|
||||
|
||||
공통 입력 스냅샷 → manifest/자산/의존성 검사 → `MakeAppx pack` → 실제 파일 내용/identity 추출 → 서명/검증 → 최종 해시·불변 저장 순서다. MakeAppx의 검증을 끄지 않는다. `.msixupload` 생성은 MakeAppx의 기본 산출물이라고 표시하지 않는다. [Microsoft MakeAppx 문서](https://learn.microsoft.com/en-us/windows/msix/package/create-app-package-with-makeappx-tool)
|
||||
|
||||
GUI/CLI는 `validate`, `plan release --target <id>`, `build --plan-id <id>`, `job status`, `export` 계약을 공유한다. v1은 `distribution=direct`, `delivery=package|appinstaller`만 지원한다. EXE·Store·bundle 요청은 `UnsupportedTarget`으로 차단한다. 다중 MSIX 대상은 직렬 실행하고 부분 실패를 전체 성공으로 표시하지 않는다.
|
||||
|
||||
서명은 OS 인증서 저장소 또는 사전 설정한 서명 공급자 프로필을 참조한다. 일반 배포 시 신뢰·Publisher 일치를 확인한다. 개발 인증서 신뢰 설정은 별도 시험 환경에서 수행하며 제작기가 사용자 PC에 인증서를 몰래 설치하지 않는다. 미서명 개발 결과의 보존은 가능하되 직접 설치/배포 준비 상태는 부여하지 않는다.
|
||||
|
||||
상태는 `Draft → Planned → Running → Built → ArtifactVerified → Finalized`이며 실패·취소·중단을 구분한다. 서명/해시 검사 성공과 VM 설치 시험 성공은 별도다. `DeploymentReady`는 해당 아티팩트 해시의 실제 증빙이 있어야 한다. 시안의 성공 표시·가상 파일 목록은 어떤 구현 작업의 완료 증빙도 아니다.
|
||||
|
||||
## 업데이트와 설치 경계
|
||||
|
||||
제작기는 상위 버전 전체 MSIX와 필요 시 `.appinstaller`를 만든다. MSIX는 블록 정보를 이용하는 Windows 차등 업데이트 경로를 활용하며 별도 MSP나 자체 차분 파일을 만들지 않는다. 전체 파일을 먼저 내려받는 자체 다운로드 코드에 전송 절감이 자동 생긴다고 가정하지 않는다. [Microsoft 차등 업데이트](https://learn.microsoft.com/en-us/windows/msix/desktop/managing-your-msix-deployment-update)
|
||||
|
||||
업데이트 설정은 사용 여부, 안내 파일 URI, 버전별 불변 MSIX URI, 실행 시 확인 간격, 사용자 안내, 필요 시 실행 전 업데이트 요구를 명시한다. Windows/스키마 지원 범위를 검사한다. 직접 설치만 선택하면 자동 업데이트가 연결된 것으로 표시하지 않는다. 패키지를 버전별 새 URL로 게시하고, App Installer 안내 파일은 명시적 갱신·이력 보존 정책을 사용한다. 업로드 자체는 첫 제품 외부의 수동 작업이다. [Store 밖 자동 업데이트](https://learn.microsoft.com/en-us/windows/msix/app-installer/auto-update-and-repair--overview)
|
||||
|
||||
설치 위치는 Windows 관리로 표시하고 임의 설치 폴더 입력을 제공하지 않는다. 사용자 데이터 폴더 선택, 개인정보 동의 수집·기록·기능 제한은 대상 앱 첫 실행 등 앱 자체의 책임이다. 패키지에 HTML을 넣었다고 설치 중 실행되거나 동의가 기록되는 것으로 간주하지 않는다. 공통 HTML 초기 설정 런타임은 후속 별도 설계다.
|
||||
|
||||
App Installer의 제한된 XML 외형 커스터마이징과 Store 표시 정보는 HTML 설치 페이지 편집과 다르다. 첫 버전은 표준 표시 메타데이터·앱 자산까지만 제공하며 XML UX 커스터마이징은 후속 검증 범위다. [App Installer UX](https://learn.microsoft.com/en-us/windows/msix/app-installer/how-to-create-custom-app-installer-ux)
|
||||
|
||||
## 제작기 디자인
|
||||
|
||||
[상호작용 시안](../../output/msix-builder-concept.html), [브라우저 미리보기](../../output/msix-builder-preview.html). 시안은 두 레이아웃을 비교하며 제품 이름, 버전, 파일, Publisher, 서명, 업데이트 설정을 로컬 예제 상태에서 바꿀 수 있다. 실제 파일을 읽거나 MakeAppx/서명/설치를 실행하지 않는다.
|
||||
|
||||
| 화면 | 제작자가 설정하는 값 | 피드백 |
|
||||
| --- | --- | --- |
|
||||
| 앱 정보 | 표시명·설명·게시자 표시명·4부분 버전·아키텍처·아이콘 | 앱 표시 정보 미리보기; 실제 Windows 설치 화면과 구별 |
|
||||
| 파일 구성 | 소스·포함/제외·패키지 상대 경로·실행 파일 | 포함 목록·충돌·누락·용량; 시안은 예제 파일 추가/제거 |
|
||||
| 패키지 설정 | Identity Name·Publisher·최소 OS·앱 선언·의존성 | manifest 요약, 지원하지 않는 시스템 작업 안내 |
|
||||
| 서명 | OS/공급자 프로필·개발/운영/미서명 | Publisher 불일치 오류, 대상 PC 신뢰와 개발 인증서 구분 |
|
||||
| 업데이트 | 직접 배포·App Installer 사용·URI·확인 간격·안내 | 생성될 파일 목록; Store와 서버 구축은 후속 |
|
||||
| 검증·빌드 | 검사·생성·취소·로그·결과 내보내기 | 단계별 상태, 오류 설정 이동, 서명/설치 시험의 독립 상태 |
|
||||
|
||||
**프로젝트 작업실형**은 왼쪽 고정 탐색, 중앙 편집, 오른쪽 미리보기/진단을 사용한다. 반복해서 제품 버전을 만드는 작업에 맞춘 기본 제안이다. **단계별 제작형**은 상단 여섯 단계와 이전/다음 흐름으로 처음 패키지를 만드는 사용자를 안내한다. 두 외형은 동일한 필드·검증·결과를 사용하며 제품 출시 시 두 화면을 모두 구현해야 한다는 요구가 아니다. MS5 착수 전에 하나를 선택한다.
|
||||
|
||||
상태 시나리오는 정상 설정, 잘못된 버전, 실행 파일 누락, Publisher/인증서 불일치, 잘못된 업데이트 URI, 미서명/개발 서명, 검사 후 설정 변경이다. 시안은 즉시 완료되는 모의 빌드를 사용한다. 실제 빌드는 도구 이벤트와 취소/중단 복구를 연결해야 한다. 출력 폴더 선택, 실파일 가져오기, 자산 크기 검사, 런타임 의존성 편집·검증, 서비스 서명은 시안에 구현되어 있지 않다.
|
||||
|
||||
## 완료 기준과 추적
|
||||
|
||||
첫 출시 범위는 [백로그](../backlog/README.md)의 1차 18개 항목과 [일정 v3](../plan/10-development-schedule.md)의 MS0~MS6다. EXE·Store·EG-BIM 업무 시험이 공통 MSIX 경로를 차단하지 않도록 의존성을 분리한다. SDK 누락, 잘못된 인증서/identity, 파일 누락, 디스크 부족, 취소/중단, 서버 연결 실패, 실행 중 업데이트, 버전 건너뛰기, 사용자 데이터 보존과 제거를 시험한다.
|
||||
|
||||
문서와 디자인 검증은 링크·JSON·의존성·브라우저 렌더링/상호작용까지다. 실제 배포 준비 판정은 구현 후 별도 Windows VM과 실제 서명으로 수행한다. [변경 기록](../changes/2026-10-19-msix-first.md)
|
||||
@@ -0,0 +1,68 @@
|
||||
# Installer Studio 프로젝트 파일 형식
|
||||
|
||||
결정일: 2026-10-26. Installer Studio의 기본 프로젝트 확장자는 **`.isproj`**다. GUI·CLI의 생성·열기·저장에 적용했다. 사용자 요청에 따라 기존 JSON 프로젝트 호환·변환은 제공하지 않는다.
|
||||
|
||||
## 형식과 용도
|
||||
|
||||
`.isproj`는 설치 패키지 제작 설정을 보관하는 UTF-8 JSON 파일이다. ZIP·XML·실행 파일이 아니며, 내부 데이터는 기존 `PackageProject v2`와 `schemaVersion: 2`를 유지한다. 확장자 변경만으로 스키마 버전을 올리지 않는다.
|
||||
|
||||
예: `EG-BIM.isproj`, `BaronViewer.isproj`. MSIX 전용 확장자로 제한하지 않으며 후속 EXE/MSI 제작에도 같은 형식을 사용한다. 최종 배포 파일인 `.msix`, `.appinstaller`, `.exe`, `.msi`, `.msp`와 구분한다.
|
||||
|
||||
[MSIX 프로젝트 예제](examples/msix.isproj)는 기존 v2 예제의 내용을 유지하고 확장자만 적용한 설계용 파일이다. 미확정 값이 포함되어 있으므로 그대로 배포용 패키지를 만들 수 있다는 의미는 아니다.
|
||||
|
||||
2026-10-27 결정: 별도의 `projectId` 필드를 화면과 저장 모델에서 제거했다. 제작기는 파일 경로로 프로젝트를 열고, MSIX 앱 계열은 `formats.msix.identity.name`과 `publisher`로 식별한다. 파일 이름이나 앱 표시 이름을 바꾸어도 MSIX Identity를 자동 변경하지 않는다. 향후 MSI 식별자도 별도로 관리한다. 새로운 제품으로 복제하는 기능은 별도의 명시적 작업으로 설계한다.
|
||||
|
||||
개발 중인 v2 계약에서 필드를 제거했으며 기존 호환·자동 변환은 제공하지 않는다. `projectId`가 남아 있는 파일은 알 수 없는 필드 오류로 거부한다. 사용자 파일과 기존 빌드 이력을 일괄 수정하지 않는다.
|
||||
|
||||
## 파일과 작업 폴더
|
||||
|
||||
```text
|
||||
project/
|
||||
EG-BIM.isproj # 공유 가능한 제품/패키지 설정
|
||||
EG-BIM.isproj.local.json # 해당 PC의 소스·SDK·서명 프로필 참조
|
||||
EG-BIM.isproj.bak # 직전 프로젝트 저장본
|
||||
EG-BIM.isproj.local.json.bak # 직전 로컬 설정 저장본
|
||||
identity.lock.json
|
||||
toolchain.lock.json
|
||||
.work/
|
||||
releases/
|
||||
patches/
|
||||
attestations/
|
||||
```
|
||||
|
||||
로컬 설정과 백업 이름은 **전체 프로젝트 파일명에 접미사를 추가**하여 계산한다. 예를 들어 `EG-BIM.isproj`에 `.local.json` 또는 `.bak`를 붙인다. `.isproj`를 `.json.bak`로 치환하지 않는다. 로컬 설정·백업·인증서 개인 키는 형상 관리에서 제외한다. 프로젝트에는 개인 키나 비밀번호를 저장하지 않는다.
|
||||
|
||||
현재 디렉터리 단위의 작업·릴리스·lock 구조를 유지하므로 **작업 폴더 하나에 프로젝트 하나**를 둔다. 다른 이름으로 저장은 별도 작업 폴더를 사용하며, 기존 이력 폴더를 자동 복사하거나 다른 프로젝트와 합치지 않는다. 상대 경로는 대상 폴더 기준으로 다시 계산하고, 연결이 깨지는 소스는 저장 전에 안내한다.
|
||||
|
||||
## 생성·열기·저장
|
||||
|
||||
| 동작 | 설계 규칙 |
|
||||
| --- | --- |
|
||||
| 새 프로젝트 | 기본 파일명 `InstallerProject.isproj`, 필터 `Installer Studio 프로젝트 (*.isproj)` |
|
||||
| 프로젝트 열기 | `.isproj` 전용 필터. 기존 `.json` 파일은 공통 로더에서도 거부한다. |
|
||||
| 확장자 처리 | `.isproj`는 대소문자 구분 없이 허용한다. 저장 이름에 확장자가 없으면 `.isproj`를 붙이고, 다른 확장자가 있으면 수정을 안내한다. `.isproj.isproj` 중복 생성을 금지한다. |
|
||||
| 내용 검사 | 확장자뿐 아니라 JSON 파싱, `schemaVersion`, 필수 필드와 지원 대상 검증을 수행한다. 일반 JSON·상위 스키마·손상 파일은 프로젝트로 취급하지 않는다. |
|
||||
| 저장 | `expectedRevision` 충돌 검사, 백업, 같은 볼륨의 임시 파일 쓰기와 원자적 교체를 사용한다. 실패 시 원본을 유지한다. |
|
||||
| 최근 프로젝트 | 실제 `.isproj` 경로를 저장한다. 기존 JSON 항목은 숨기고 해당 ID로도 열지 못하게 한다. 기존 파일은 삭제하지 않는다. |
|
||||
| CLI | `--project .\EG-BIM.isproj`를 표준 예제로 사용한다. GUI와 같은 로더·검증기를 공유한다. |
|
||||
|
||||
Windows 탐색기 연결은 후속 구현 항목이다. `.isproj`에 Installer Studio 아이콘과 열기 동작을 연결하고, 더블 클릭으로 받은 경로는 일반 프로젝트 열기와 같은 검증 및 미저장 변경 보호를 거친다. 경로를 셸 명령으로 실행하지 않는다. `.json` 전체의 기본 연결은 변경하지 않는다.
|
||||
|
||||
## 기존 형식 미지원과 구현 범위
|
||||
|
||||
기존 `.json` 프로젝트는 GUI·CLI·최근 목록을 포함한 모든 열기 경로에서 거부한다. 확장자를 생략한 새 프로젝트 이름에만 `.isproj`를 붙인다. `.json`을 지정한 생성 요청은 자동 변경하지 않는다.
|
||||
|
||||
기존 `package-project.local.json`으로 폴백하지 않는다. `.isproj.local.json`이 없으면 빈 로컬 설정으로 열고 소스·도구를 사용자가 연결한다. 기존 사용자 파일과 이력은 삭제하거나 이름을 바꾸지 않는다. 실행용 fixture와 새 샘플 생성 스크립트는 `.isproj`로 갱신했다.
|
||||
|
||||
일반 저장은 로컬 설정을 먼저 원자적으로 교체하고 프로젝트 교체가 실패하면 로컬 설정을 복구한다. 각 파일의 교체는 원자적이지만 프로세스 강제 종료·전원 차단까지 포함한 두 파일의 트랜잭션은 보장하지 않는다. 직전 `.bak` 파일을 보존한다.
|
||||
|
||||
탐색기 연결, 다른 이름으로 저장, 작업 폴더당 프로젝트 하나의 강제 검사는 후속 항목이다. 현재는 새 프로젝트와 일반 열기·저장을 지원한다.
|
||||
|
||||
## 구현 시 확인할 항목
|
||||
|
||||
- GUI의 생성·열기·저장 필터와 CLI가 `.isproj`를 같은 방식으로 처리하는지 확인한다.
|
||||
- 한글·공백이 있는 파일명, 대문자 확장자, 확장자 생략·중복 입력을 확인한다.
|
||||
- 기존 JSON 거부, 기존 로컬 설정 미참조, `.isproj`의 소스·SDK·서명 참조 저장을 확인한다.
|
||||
- 프로젝트 ID 없이 생성·저장·열기·빌드가 가능하고, 일반 저장 전후 패키지 identity가 바뀌지 않는지 확인한다.
|
||||
- 백업 이름, 외부 변경 충돌, 중간 저장 실패, 상대 경로 및 최근 목록 갱신을 확인한다.
|
||||
- 탐색기 연결은 앱 배포 방식별 등록·제거와 경로 인자 전달을 별도 검증한다.
|
||||
+24
-11
@@ -1,13 +1,16 @@
|
||||
# 설치 패키지 자동화 생성 프로그램 설계
|
||||
|
||||
작성 기준: 2026-10-16. 대상 제품: EG-BIM/Baron. 구현 언어는 **Rust**, 데스크톱 화면은 **Tauri 기반 웹 UI**로 확정한다. 이 문서들은 구현 전 설계이며 실행 가능한 프로그램이나 검증된 설치 패키지는 아직 없다.
|
||||
작성 기준: 2026-10-16. 2026-10-19 범위 정정: **범용 Windows 설치 패키지 제작기**이며 EG-BIM/Baron은 적용 사례다. 구현 언어는 **Rust**, 데스크톱 화면은 **Tauri 기반 웹 UI**로 확정한다. 이 문서들은 구현 전 설계이며 실행 가능한 프로그램이나 검증된 설치 패키지는 아직 없다.
|
||||
|
||||
프로그램은 설치 파일 목록, 설치 위치, 레지스트리, 버전·GUID를 프로젝트로 관리하고, 전체 릴리스와 기준 버전별 패치를 생성한다. GUI와 CI용 CLI가 같은 Rust 엔진을 사용한다. 패키지 생성 백엔드는 기존 검토를 이어 **WiX MSI/MSP + Burn EXE**를 기준으로 설계한다.
|
||||
현재 첫 버전은 **MSIX 제작기**다. GUI와 CI용 CLI가 같은 Rust 엔진과 **Windows SDK MakeAppx + manifest** 백엔드를 사용한다. EXE/MSI/MSP/Burn·HTML 설치 마법사는 후속 단계로 유지한다. Store 제출도 후속이며 직접 배포에 Store 계정을 요구하지 않는다. [12번 MSIX 우선 설계](12-msix-first-builder.md)가 현재 범위/완료 기준이고 [11번](11-generic-exe-msix-architecture.md)은 장기 두 형식 확장 구조다.
|
||||
|
||||
## 문서 구성
|
||||
|
||||
2026-10-26 추가 결정: 프로그램 명칭은 **Installer Studio**, 프로젝트 확장자는 **`.isproj`**다. 내부 형식은 JSON v2를 유지하며 기존 JSON 호환은 제공하지 않는다. [13번 파일 형식 설계](13-isproj-project-format.md)를 파일 다이얼로그·저장소에 적용했으며 탐색기 연결은 후속 작업이다.
|
||||
|
||||
| 문서 | 설계 내용 |
|
||||
| --- | --- |
|
||||
| [프로그램 설계서 — Word](../program-design/MSIX-프로그램-설계서.docx) | 참고 Google Docs 양식을 적용한 MSIX 우선 통합 설계서: 기능 정의·흐름도·화면·인터페이스·검증·일정 |
|
||||
| [01 구조와 모듈](01-architecture.md) | Tauri, Rust 공통 엔진, CLI, 작업 실행과 저장 구조 |
|
||||
| [02 프로젝트와 데이터 모델](02-project-model.md) | 설정 파일, 파일 목록, 릴리스 기록, 예제 JSON |
|
||||
| [03 파일·설치 위치·레지스트리](03-files-and-registry.md) | 파일 수집, 컴포넌트, 설치 경로, 레지스트리 작성 규칙 |
|
||||
@@ -17,29 +20,39 @@
|
||||
| [07 화면과 명령 인터페이스](07-ui-and-commands.md) | 화면별 기능, Tauri IPC, 작업 이벤트, CLI |
|
||||
| [08 검증과 구현 순서](08-validation-and-roadmap.md) | 자동 검증, Windows VM 시험, 단계별 완료 기준 |
|
||||
| [09 설치 과정과 UI 편집](09-install-flow-and-ui.md) | 단계 추가·삭제·순서·조건, UI 테마, 사용자 정의 Burn 화면 |
|
||||
| [프로젝트 예제](examples/egbim.package-project.json) | 설계용 초기 프로젝트 설정 |
|
||||
| [10 설치 마법사 재설계](10-installer-wizard-redesign.md) | InstallShield/Inno Setup 패턴, 5개 모드, 페이지·취소·실패·재부팅 및 편집 화면 계약 |
|
||||
| [12 MSIX 우선 제작기](12-msix-first-builder.md) | 현재 1차 범위, 생성 계약, 제작 화면, 검증 기준 |
|
||||
| [13 프로젝트 파일 형식](13-isproj-project-format.md) | `.isproj`, JSON v2 내용, 로컬 설정·백업 이름, 기존 JSON 거부와 GUI/CLI 규칙 |
|
||||
| [MSIX-only 예제](examples/msix.package-project.json) | EXE 설정이 없는 현재 설계용 입력 |
|
||||
| [11 범용 EXE·MSIX 구조](11-generic-exe-msix-architecture.md) | 제품 범위, 출력/배포 분리, MSIX 계약과 완료 기준 |
|
||||
| [범용 프로젝트 예제 v2](examples/generic.package-project.json) | 두 형식을 함께 요청하는 미확정 설계 입력 |
|
||||
| [EG-BIM 프로젝트 예제 v1](examples/egbim.package-project.json) | 이전 EXE 전용 초안; v2 가져오기 대상 |
|
||||
|
||||
## 범위와 결정
|
||||
|
||||
| 구분 | 내용 |
|
||||
| --- | --- |
|
||||
| 필수 | 파일·폴더 등록, 포함/제외, 설치 경로, 레지스트리, 버전/GUID, 전체 릴리스, 버전별 MSP |
|
||||
| 필수 | PE·MSI·MSP·Burn 서명 연동, 2GB 초과 전체 용량 대응, 기준 릴리스 보존, 검증 보고서 |
|
||||
| 필수 | 제작자의 설치 과정 추가·삭제·조건 편집, 설치 UI 커스터마이징; 표준 테마와 사용자 정의 BA의 지원 범위 구분 |
|
||||
| 1차 필수 | 공통 제품/파일 설정, MSIX 생성, 서명·검증·불변 보관·내보내기·GUI/CLI |
|
||||
| 후속 — EXE | 설치 경로, 레지스트리, 버전/GUID, 전체 릴리스, 버전별 MSP |
|
||||
| 1차 필수 — MSIX | manifest/identity/자산/의존성, MakeAppx 생성, 직접 배포 서명, 버전별 업데이트 |
|
||||
| 후속 — EXE | PE·MSI·MSP·Burn 서명 연동, 대용량 CAB, MSP 기준 보존 |
|
||||
| 후속 — EXE | 제작자의 설치 과정 추가·삭제·조건 편집, 설치 UI 커스터마이징; 표준 테마와 사용자 정의 BA의 지원 범위 구분 |
|
||||
| 확정 | Windows 대상, InstallShield 중단, Rust + Tauri |
|
||||
| 설계 제안 | Tauri 2, TypeScript + React + Vite, JSON 프로젝트, WiX/Burn 백엔드 |
|
||||
| 설계 제안 | Tauri 2, TypeScript + React + Vite, JSON v2, MakeAppx/SignTool; WiX/Burn은 후속 |
|
||||
| 연계 | 업로드용 메타데이터 내보내기, 개발자→1차→2차→사용자 배포에 동일 아티팩트 사용 |
|
||||
| 별도 시스템 | 배포 서버·그룹 승인, EG-BIM의 실제 자동 업데이트 실행부, Store 제출 |
|
||||
| 후속 검토 | MSIX 출력, 클라우드 업로드 어댑터, 기존 ISM의 자동 가져오기 |
|
||||
| 후속 검토 | MSIX 다중 아키텍처 bundle, 클라우드 업로드 어댑터, 기존 ISM의 자동 가져오기 |
|
||||
|
||||
Tauri는 **생성 프로그램의 화면과 데스크톱 실행 환경**이다. Tauri가 자체 앱을 배포하는 번들러와 EG-BIM 패키지를 만드는 엔진은 별개다. EG-BIM을 Tauri 앱으로 바꾸거나, Tauri 업데이터를 기존 제품에 바로 적용한다는 뜻이 아니다.
|
||||
Tauri는 **생성 프로그램의 화면과 데스크톱 실행 환경**이다. Tauri가 제작기 자체를 배포하는 번들러와 고객 제품의 EXE/MSIX를 만드는 엔진은 별개다. EG-BIM을 Tauri 앱으로 바꾸거나, Tauri 업데이터를 기존 제품에 바로 적용한다는 뜻이 아니다.
|
||||
|
||||
기존 설치 기본 경로 `C:\Program Files\Baron\EG-BIM`을 유지한다. 실제 설치 파일 목록은 별도로 확정해야 하며 `D:\egbim\repo\14.1` 전체를 배포 파일로 취급하지 않는다. InstallShield 제거 스크립트가 사용자 데이터를 지울 수 있으므로 최초 전환에는 백업·복원 검증이 필요하다. [기존 현황](../plan/01-requirements-and-current-state.md), [설치기 전환](../plan/02-installer-migration.md)
|
||||
EG-BIM EXE 적용 사례에서는 기존 설치 기본 경로 `C:\Program Files\Baron\EG-BIM`을 유지한다. 실제 설치 파일 목록은 별도로 확정해야 하며 `D:\egbim\repo\14.1` 전체를 배포 파일로 취급하지 않는다. InstallShield 제거 스크립트가 사용자 데이터를 지울 수 있으므로 최초 전환에는 백업·복원 검증이 필요하다. [기존 현황](../plan/01-requirements-and-current-state.md), [설치기 전환](../plan/02-installer-migration.md)
|
||||
|
||||
전체 설치 결과는 단일 EXE로 한정하지 않는다. 대용량 기본 출력은 `Setup.exe + MSI + 분할 CAB + 필수 런타임` 레이아웃이며, 네트워크용 EXE는 필요한 데이터를 내려받는다. Store용 단일 오프라인 설치 파일은 용량과 제출 요건을 통과한 경우에만 생성한다.
|
||||
EXE 출력의 전체 설치 결과는 단일 파일로 한정하지 않는다. 대용량 기본 출력은 `Setup.exe + MSI + 분할 CAB + 필수 런타임` 레이아웃이며, 네트워크용 EXE는 필요한 데이터를 내려받는다. 직접 배포용 단일 오프라인 EXE도 지원하며, Store 대상은 제출 요건을 추가 검사한다. MSIX는 Store와 관계없이 별도 백엔드에서 생성한다.
|
||||
|
||||
## 완료된 설계와 남은 확정 사항
|
||||
|
||||
문서의 타입·명령·파일 형식은 구현 계약 제안이다. 도구의 정확한 버전, 제조사 표시명, 실제 배포 소스 폴더, 필수 런타임 목록, 서명 프로필, 지원 기준 릴리스는 첫 구현 단계에서 확정한다. 값이 비어 있거나 검증되지 않은 프로젝트는 편집·미리보기만 허용하고 정식 릴리스 확정은 차단한다.
|
||||
|
||||
기존 운영 정책은 [배포 계획](../plan/README.md)을 따른다. 이 설계에서는 생성 프로그램의 책임과 출력 계약을 구체화한다.
|
||||
|
||||
2026-10-19 검토에서 통합 구현 순서를 [백로그](../backlog/README.md)와 [단독 개발 일정](../plan/10-development-schedule.md)으로 정리했다. AI 지원 없이 개발자 1명이 제작기·업데이터·서버·검증을 수행하는 기준이며, 현재는 MSIX 작은 빌드·서명·업데이트 실험을 초기에 배치하고 전환/BA 실험은 후속으로 이월한다.
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"product": {
|
||||
"displayName": "Sample Desktop Tool",
|
||||
"manufacturer": "Example Publisher",
|
||||
"displayVersion": "1.0.0"
|
||||
},
|
||||
"sources": [{ "alias": "appPayload" }],
|
||||
"files": [{ "id": "application", "source": "appPayload", "include": ["**/*"], "exclude": [], "targetRelativePath": "", "required": true }],
|
||||
"formats": {
|
||||
"exe": {
|
||||
"msiVersion": "1.0.0",
|
||||
"architecture": "x64",
|
||||
"upgradeCode": null,
|
||||
"installScope": "perMachine",
|
||||
"installRoot": "[ProgramFiles64Folder]ExamplePublisher\\SampleDesktopTool",
|
||||
"registry": [],
|
||||
"prerequisites": [],
|
||||
"patchPolicy": { "enabled": true },
|
||||
"installationFlow": { "template": "standard" },
|
||||
"installerUi": { "template": "standard-wizard" }
|
||||
},
|
||||
"msix": {
|
||||
"identity": { "name": "ExamplePublisher.SampleDesktopTool", "publisher": null, "version": "1.0.0.0", "architecture": "x64" },
|
||||
"minimumOsVersion": "10.0.19041.0",
|
||||
"applications": [{ "id": "App", "executable": "SampleTool.exe", "entryPoint": "Windows.FullTrustApplication", "square44x44Logo": "Assets/Logo44.png", "square150x150Logo": "Assets/Logo150.png" }],
|
||||
"capabilities": ["runFullTrust"],
|
||||
"extensions": [],
|
||||
"dependencies": []
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{ "id": "exe-direct", "format": "exe", "delivery": "offline-singlefile", "distribution": "direct", "signingProfileRef": null },
|
||||
{ "id": "msix-direct", "format": "msix", "delivery": "package", "distribution": "direct", "signingProfileRef": null }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"product": {
|
||||
"displayName": "Sample Desktop Tool",
|
||||
"manufacturer": "Example Publisher",
|
||||
"displayVersion": "1.0.0"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"alias": "appPayload"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": "application",
|
||||
"source": "appPayload",
|
||||
"include": [
|
||||
"**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"targetRelativePath": "",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"formats": {
|
||||
"msix": {
|
||||
"identity": {
|
||||
"name": "ExamplePublisher.SampleDesktopTool",
|
||||
"publisher": null,
|
||||
"version": "1.0.0.0",
|
||||
"architecture": "x64"
|
||||
},
|
||||
"minimumOsVersion": "10.0.19041.0",
|
||||
"applications": [
|
||||
{
|
||||
"id": "App",
|
||||
"executable": "SampleTool.exe",
|
||||
"entryPoint": "Windows.FullTrustApplication",
|
||||
"square44x44Logo": "Assets/Logo44.png",
|
||||
"square150x150Logo": "Assets/Logo150.png"
|
||||
}
|
||||
],
|
||||
"capabilities": [
|
||||
"runFullTrust"
|
||||
],
|
||||
"extensions": [],
|
||||
"dependencies": []
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"id": "msix-direct",
|
||||
"format": "msix",
|
||||
"delivery": "package",
|
||||
"distribution": "direct",
|
||||
"signingProfileRef": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"product": {
|
||||
"displayName": "Sample Desktop Tool",
|
||||
"manufacturer": "Example Publisher",
|
||||
"displayVersion": "1.0.0"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"alias": "appPayload"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"id": "application",
|
||||
"source": "appPayload",
|
||||
"include": [
|
||||
"**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"targetRelativePath": "",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"formats": {
|
||||
"msix": {
|
||||
"identity": {
|
||||
"name": "ExamplePublisher.SampleDesktopTool",
|
||||
"publisher": null,
|
||||
"version": "1.0.0.0",
|
||||
"architecture": "x64"
|
||||
},
|
||||
"minimumOsVersion": "10.0.19041.0",
|
||||
"applications": [
|
||||
{
|
||||
"id": "App",
|
||||
"executable": "SampleTool.exe",
|
||||
"entryPoint": "Windows.FullTrustApplication",
|
||||
"square44x44Logo": "Assets/Logo44.png",
|
||||
"square150x150Logo": "Assets/Logo150.png"
|
||||
}
|
||||
],
|
||||
"capabilities": [
|
||||
"runFullTrust"
|
||||
],
|
||||
"extensions": [],
|
||||
"dependencies": []
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"id": "msix-direct",
|
||||
"format": "msix",
|
||||
"delivery": "package",
|
||||
"distribution": "direct",
|
||||
"signingProfileRef": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
# 요구사항과 기존 프로그램 현황
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
제품의 공통 요구는 여러 제품의 EXE·MSIX 설치 패키지를 만드는 범용 제작기다. 아래 경로·GUID·수량·기존 업데이터 분석은 **EG-BIM 적용 사례**의 현황이며 공통 엔진 기본값이나 모든 제품의 선행 조건이 아니다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
EG-BIM의 기존 설치 기반을 보존하면서 네트워크 배포를 추가한다. 설치 도구 변경과 앱 구조 변경을 한 번에 강제하지 않는 방향으로 검토한다.
|
||||
|
||||
## 확정 요구사항
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# InstallShield 대체와 기존 설치본 전환
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
이 문서는 EG-BIM의 InstallShield→EXE/MSI 전환 적용 계획이다. 범용 제작기는 별도로 MSIX 출력도 필수 지원한다. 다른 제품의 패키지 생성에 EG-BIM 자료나 구버전 제거를 요구하지 않는다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
권고안은 WiX로 MSI를 작성하고 Burn으로 필수 런타임과 MSI를 묶은 전체 설치 EXE를 만드는 것이다. 사용자에게는 기존처럼 EXE 설치 파일을 제공할 수 있다. WiX 채택과 도구 버전·이용 조건은 구현 시작 전에 확정한다.
|
||||
|
||||
## 대체 도구 검토
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 버전별 패키지 관리와 업로드
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
불변 아티팩트·해시·증빙 원칙은 EXE와 MSIX에 공통 적용한다. MSI/MSP 식별자와 기준 상태는 EXE 대상에만 적용하고 MSIX identity/업데이트 경로는 별도 기록한다. 아래 서버 업로드는 선택한 배포 연계의 책임이며 로컬 빌드의 필수 의존성이 아니다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
패키지는 등록 후 변경하지 않고 배포 정책만 변경한다. 같은 릴리스를 개발자 테스트부터 일반 배포까지 사용하며, 수정이 필요하면 새 릴리스를 만든다.
|
||||
|
||||
## 버전 및 관리 정보
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 사용자 그룹별 4단계 배포
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
이 문서는 자체 서버와 EG-BIM 적용 트랙의 단계 배포 계약이다. 범용 EXE/MSIX 생성은 이 서버 없이 가능해야 한다. Store 공개·MSIX 업데이트는 각 배포 대상의 별도 정책을 사용하며 서버 승인 상태와 동일시하지 않는다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
하나의 릴리스를 네 그룹에 순차적으로 공개한다. 초기에는 담당자가 관측 결과를 확인한 후 다음 단계를 승인하는 방식을 권고한다.
|
||||
|
||||
## 그룹 구성
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Microsoft Store 배포 방식
|
||||
|
||||
현재 EG-BIM에는 자체 업데이터와 PC 전체 설치 구조가 있으므로 MSI·EXE 등록 경로를 우선 검토한다. Store 배포에 MSIX가 반드시 필요한 것은 아니다.
|
||||
처음 등록하는 담당자는 [초보자용 Store 배포 매뉴얼](../manuals/microsoft-store/README.md)을 따른다. 2026-10-26 확인한 계정 가입 절차와 현재 제작기의 지원 범위를 별도로 설명한다. 이 문서의 출력 계약은 설계이며 현재 구현 완료 목록이 아니다.
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
**Store는 범용 제작기의 출력 파일을 등록하는 배포 채널이다.** 제작기는 Store 등록 여부와 관계없이 EXE와 MSIX를 모두 생성한다. 제품마다 적합한 형식으로 등록하며 EG-BIM의 기존 구조만으로 범용 제품의 형식을 제한하지 않는다. [출력과 배포 대상 계약](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
## 두 경로의 차이
|
||||
|
||||
@@ -11,7 +15,7 @@
|
||||
| 업데이트 | 자체 업데이터 담당 | Store 관리 |
|
||||
| 지정 테스터 배포 | 자체 서버에서 구현 | Package Flights 지원 |
|
||||
| 비율 배포 | 자체 서버에서 구현 | Store 점진 업데이트 지원 |
|
||||
| 현재 앱 적용 | 기존 경로와 설치 기능을 유지하는 방향 | 경로·레지스트리·CAD 연동·업데이터 검증 필요 |
|
||||
| 제품별 적합성 | 기존 설치 경로와 무인 실행 동작 검증 | 패키지 identity·선언 기능·앱 동작 검증; CAD 연동은 해당 제품만 추가 |
|
||||
|
||||
[Microsoft 배포 방식 비교](https://learn.microsoft.com/en-us/windows/apps/distribute-through-store/how-to-distribute-your-win32-app-through-microsoft-store)
|
||||
|
||||
@@ -25,9 +29,9 @@
|
||||
|
||||
Store용은 필요한 오프라인 런타임과 MSI를 포함한 단일 `FullSetup.exe` 등 제출 요건을 만족하는 파일로 만든다. 대용량으로 단일 파일의 생성·서명 제한을 넘으면 이 경로를 사용 가능하다고 간주하지 않는다. 자체 배포용 분할 CAB 폴더나 작은 `WebSetup.exe`가 그대로 Store 제출을 대신하는 것은 아니다. 현재 `.ism`의 웹 설치형 선행 조건은 그대로 이관하지 않고 실제 의존성을 정리한다. [공식 패키지 요구사항](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msi/app-package-requirements), [출력 프로필과 용량 검사](../code-design/05-release-pipeline.md)
|
||||
|
||||
## 자체 배포와 함께 운영
|
||||
## EXE 자체 배포와 함께 운영
|
||||
|
||||
자체 사이트와 Store에서 같은 검증 완료 전체 설치 파일을 사용할 수 있다. Store에는 일반 사용자에게 공개할 릴리스만 등록한다. 최초 설치 후의 업데이트는 자체 서버가 그룹별로 제어한다.
|
||||
자체 사이트와 Store에서 같은 검증 완료 전체 설치 파일을 사용할 수 있다. EG-BIM 적용 정책에서는 Store에 일반 사용자에게 공개할 릴리스만 등록한다. 다른 제품의 공개 정책은 해당 프로젝트에서 정한다. 최초 설치 후의 업데이트는 자체 서버가 그룹별로 제어한다.
|
||||
|
||||
Store MSI·EXE 등록은 자체 서버의 4단계 배포 정책을 대신하지 않는다. 자체 서버의 배포 중지와 Store의 새 사용자 설치 중지는 별도 조치다. 두 경로의 공개 상태와 설치 패키지 버전을 함께 기록해야 한다.
|
||||
|
||||
@@ -35,16 +39,29 @@ Store 등록·심사 시점과 자체 배포 시점을 조정하고, Store의
|
||||
|
||||
Store의 신규 설치용 등록 파일은 항상 전체 MSI·EXE로 유지한다. MSP를 신규 설치 파일 대신 제출하지 않는다. 설치 이후 자체 업데이터는 [버전별 패치 정책](08-version-patching.md)에 따라 호환되는 MSP를 적용할 수 있으며, 해당 버전의 전체 설치본과 패치 적용 결과가 같은 관리 상태가 되는지 검증한다.
|
||||
|
||||
## MSIX로 전환할 경우
|
||||
## 제작한 MSIX를 Store에 제출할 경우
|
||||
|
||||
Package Flights에 개발자·1차·2차 테스트 그룹을 구성하고 정식 제출을 일반 사용자 단계에 연결할 수 있다. Microsoft 계정으로 테스터를 등록하고 Flight도 인증 절차를 거친다. 초기 앱 제출 게시 후 Flight를 구성하는 흐름을 고려한다. [Package Flights](https://learn.microsoft.com/en-us/windows/apps/publish/package-flights)
|
||||
|
||||
Store 점진 배포는 기존 사용자의 업데이트에 대한 비율 제어다. 최초 설치에도 같은 비율 제한이 적용된다고 가정하지 않는다. 중지는 이미 업데이트된 앱을 이전 버전으로 되돌리지 않으므로 수정 릴리스를 준비해야 한다. [점진 배포](https://learn.microsoft.com/en-us/windows/apps/publish/gradual-package-rollout)
|
||||
|
||||
MSIX 전환 시에는 고정 설치 경로, 설치 위치 쓰기, 외부 CAD·플러그인·COM 연동, 사용자 설정 이동, 런타임을 검증한다. 현재 구조만으로 불가능하다고 판정한 것은 아니다. [MSIX 준비 사항](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-prepare)
|
||||
기존 제품을 MSIX로 배포하려면 설치 위치 쓰기, 외부 연동, 데이터 이전, 런타임을 제품별로 검증한다. EG-BIM의 CAD·플러그인·COM 적합성은 별도 검토다. 범용 MSIX 출력 기능을 이 제품의 전환 성공에 종속시키지 않는다. [MSIX 준비 사항](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-prepare)
|
||||
|
||||
## SmartScreen과 설치 경로
|
||||
|
||||
Microsoft 공식 안내는 Store를 통한 MSI·EXE 설치 과정에는 SmartScreen 경고가 없고 UAC는 나타날 수 있다고 구분한다. 이는 Microsoft가 해당 EXE를 재서명한다는 의미가 아니다. Store에서 제공하는 MSIX 패키지 서명 처리와 다르다.
|
||||
|
||||
같은 EXE를 자체 웹사이트에서 내려받으면 일반 다운로드의 SmartScreen 평판 판단을 받는다. Store 등록만으로 자체 배포 URL까지 경고 면제가 되지는 않는다. Store 설치 후 자체 업데이터가 내려받는 파일도 별도의 서명·검증이 필요하며 Store 설치 경로의 효과를 그대로 가정하지 않는다. [코드 서명 및 배포 경로 비교](https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/code-signing-options)
|
||||
|
||||
## 등록 전 제작기의 산출물
|
||||
|
||||
| 출력 대상 | 생성/검증 | 등록 단계 |
|
||||
| --- | --- | --- |
|
||||
| 직접 배포 EXE | 단일/분할/네트워크 구성과 자체 서명 | 자체 배포; Store 불필요 |
|
||||
| Store EXE | 완전 오프라인 단일 파일, 서명, 무인 설치 인자와 제출 검사 보고서 | 고정 HTTPS URL과 등록 자료를 별도로 제출 |
|
||||
| 직접 배포 MSIX | manifest·MakeAppx 패키지·신뢰 가능한 서명; 선택적으로 App Installer | 직접 설치/기업 배포; Store 불필요 |
|
||||
| Store MSIX | Store identity를 적용한 `.msix`, 제출 검사 보고서 | Partner Center 업로드, 심사 후 Store 배포 서명 |
|
||||
|
||||
MSIX 자체 생성은 1차 필수다. Store 제출용 내보내기 계약과 등록은 후속 범위다. 실제 계정 설정·등록·심사·공개 운영은 BL-44/45의 선택 작업이다. Store 제출 파일은 직접 설치용 서명본과 별도 아티팩트로 관리한다. [MSIX 업로드 지원 형식](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/upload-app-packages)
|
||||
|
||||
설치 경로와 UI는 배포 채널이 아니라 형식의 제약을 따른다. EXE는 제품 프로젝트가 정한 경로/기본값과 무인 인자를 사용한다. MSIX는 Windows가 경로를 관리하므로 제작기에 임의 설치 폴더나 Burn 마법사 편집을 제공하지 않는다. 앱 데이터 경로는 패키지 설치 위치와 분리한다. [MSIX 파일 배치](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes)
|
||||
@@ -1,5 +1,9 @@
|
||||
# 코드 서명 서비스와 SmartScreen
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
EXE 내부 PE·MSI·MSP·Burn의 서명 순서와 MSIX 패키지 서명을 구분한다. 직접 배포 MSIX는 manifest Publisher와 인증서 Subject 일치 및 대상 PC의 신뢰를 검사한다. Store MSIX 제출 파일과 Store가 최종 서명한 배포 파일의 상태·해시는 별도이며, 제출용 미서명 파일을 직접 배포 준비 완료로 표시하지 않는다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
WiX는 설치 패키지 생성 도구다. 회사 명의의 코드 서명 인증서 또는 서명 서비스는 별도로 준비해야 한다. WiX 빌드에서 서명 도구를 호출해 자동화할 수 있다.
|
||||
|
||||
## 역할과 서비스 선택
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
# 구현 순서와 검증 계획
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
현재 제품 완료 기준에는 **EXE와 MSIX 생성·검증**이 모두 포함된다. 아래 legacy 전환·자체 서버·4단계 배포는 EG-BIM 적용·연계 트랙이다. 범용 제작기는 두 독립 가상 제품에서 두 형식의 설치/업데이트/제거를 검증하며 EG-BIM 전환·Store 심사를 공통 생성 차단 조건으로 두지 않는다. 통합 순서는 [일정 v2](10-development-schedule.md)와 BL-46~53을 포함한 백로그를 따른다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
첫 검증 목표는 기존 InstallShield 설치본을 새 설치본으로 전환하면서 사용자 설정과 CAD 연동을 보존하는 것이다. 이 경로를 검증한 뒤 서버의 단계 배포를 연결한다.
|
||||
|
||||
영역별 구현 항목은 아래 목록을 유지한다. 2026-10-19 기준 통합 실행 순서와 인력·일정은 [개발 일정과 마일스톤](10-development-schedule.md), 개별 작업의 선행 조건과 완료 기준은 [구현 백로그](../backlog/README.md)를 따른다.
|
||||
|
||||
## 구현 전 결정할 항목
|
||||
|
||||
| 항목 | 현재 상태 | 필요한 결정·확인 |
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 버전별 패치와 복구
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
이 문서의 MSP·MSI 기준 상태·Burn 적용 경로는 **EXE/MSI 제품 전용**이다. 범용 제작기의 MSIX 출력은 버전 증가 패키지로 업데이트하며 MSP를 적용하지 않는다. EXE↔MSIX 전환은 별도 데이터 이전·공존 검증이 필요한 작업이다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md) 참조.
|
||||
|
||||
버전별 패치는 필수 요구사항이다. 현재 설치된 버전과 상태를 확인해 변경분만 적용할 수 있어야 하며, 신규 설치·최초 설치기 전환·패치 비호환 상태를 위한 전체 설치 패키지도 함께 제공한다.
|
||||
|
||||
## 권장 구현 방식
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# 계획 검토 결과
|
||||
|
||||
현재 1차 범위는 [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)다. EXE/MSP·EG-BIM 전환·자체 그룹 배포·Store 제출은 후속으로 유지하며 첫 출시 의존성에서 제외한다. 아래 기존 분석/확장 계약보다 이 범위와 [일정 v3](10-development-schedule.md)가 우선한다.
|
||||
|
||||
범위 정정: 초기 검토의 EG-BIM 중심 가정과 MSIX 후순위 분류를 수정했다. [범용 출력 설계](../code-design/11-generic-exe-msix-architecture.md)와 [변경 기록](../changes/2026-10-19-general-package-builder.md)이 현재 기준이다. 기존 위험 분석은 해당 EXE/EG-BIM 적용 범위에서 유효하다.
|
||||
|
||||
초기 검토일: 2026-10-19, Asia/Seoul. 초기 검토 대상은 `docs/plan/01~08`, `docs/code-design/01~09`, 프로젝트 JSON 예제와 설치 화면 시안이다. 이번 검토는 문서의 범위·의존성·완료 기준을 대조한 것이다. 기존 EG-BIM 소스나 실제 출시 설치 파일을 다시 조사하거나 Windows 설치 시험을 실행한 결과는 아니다. 외부 서비스 가격·가입 자격·Store 정책도 초기 검토에서는 재확인하지 않았다. 이후 범용 범위 정정에서는 MakeAppx·MSIX 서명/버전·Store 제출 공식 문서를 확인하고 11번 설계에 근거를 연결했다. 서비스 가격·계약 자격은 재검토 범위가 아니다.
|
||||
|
||||
## 판단
|
||||
|
||||
범용 EXE·MSIX 제작을 중심으로 형식별 업데이트와 사용자 데이터 보존·불변 아티팩트를 유지한다. 먼저 두 형식의 작은 빌드/설치 실험과 공통 모델을 검증한다. EG-BIM 적용에는 실제 구버전 설치본 확보와 전환·패치·설치 UI 실험을 추가한다.
|
||||
|
||||
현재 저장소에는 계획·설계·시안이 있으며 실행 가능한 Rust/Tauri 제작기, WiX 패키지, 업데이터 연동, 서버 구현은 없다. 설계에 적혀 있는 기능을 구현 완료로 간주하지 않는다. 아래 백로그의 구현 항목은 모두 미착수로 시작한다.
|
||||
|
||||
## 주요 발견과 조치
|
||||
|
||||
| ID | 중요도 | 근거와 발견 | 영향 및 권고 조치 | 연결 백로그 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| R01 | 높음 | [운영 구현 순서](07-implementation-and-validation.md)는 전환 보존을 첫 목표로 두지만 [코드 구현 순서](../code-design/08-validation-and-roadmap.md)는 실제 EG-BIM 전환을 UI 뒤에 배치한다. | 순서가 다른 두 목록은 제품 전체의 일정을 제공하지 못한다. 실제 구버전 제거 영향 실험을 초반에 하고, 본 전환 구현을 패치·GUI 완성보다 앞에 둔다. | BL-01, BL-07, BL-22 |
|
||||
| R02 | 높음 | [설치 UI 설계](../code-design/09-install-flow-and-ui.md)는 Rust/Burn 연결과 WebView2 없는 PC의 시작 경로를 미검증으로 명시한다. | 자유로운 페이지 편집을 구현한 뒤 실행 백엔드가 불가능하다고 판명될 수 있다. 최소 BA 연결 실험을 초기에 실시하고 실패 시 대안·유지보수 비용을 기록한다. 기본 테마만으로 자유 페이지 요구를 완료 처리하지 않는다. | BL-08, BL-31, BL-32 |
|
||||
| R03 | 높음 | [전체 릴리스](../code-design/05-release-pipeline.md)와 [패치 설계](../code-design/06-patch-pipeline.md)는 같은 ProductCode의 전체 대체 경로와 Burn/MSP 유지보수를 미검증으로 남긴다. | MSP 생성 성공만으로 배포할 수 없다. 실제 source state별 전체 대체 경로와 repair·제거·다음 업데이트를 패치 완료의 필수 조건으로 묶는다. | BL-04, BL-25~28 |
|
||||
| R04 | 높음 | [프로젝트 예제](../code-design/examples/egbim.package-project.json)의 제조사·서명 프로필은 비어 있고 런타임·레지스트리·전환 검증 플래그는 미확정이다. | 실제 payload와 출시본 목록이 없으면 일정과 설치 결과를 검증할 수 없다. 확인 자료를 별도 관리하고 초안 프로젝트의 정식 릴리스 확정을 차단한다. | BL-01~03, BL-10 |
|
||||
| R05 | 높음 | [생성기 상태](../code-design/05-release-pipeline.md)의 `Finalized/DeploymentReady`와 [서버 상태](03-package-and-upload.md)의 `Uploaded/Verified/Ready`가 각각 존재한다. | 서로 다른 검증 범위를 같은 성공으로 해석할 위험이 있다. 상태 간 매핑, 증빙 발급 주체, 누락·만료·철회 처리를 하나의 내보내기/수신 계약으로 정의한다. | BL-20, BL-34, BL-35 |
|
||||
| R06 | 높음 | [기존 업데이트 현황](01-requirements-and-current-state.md)은 NuGet 호출부만 확인했고, 사용자 채널과 장치 단위 배포 그룹의 대응도 미정이다. | 기존 라이브러리 재사용을 전제로 일정 단축을 계산하지 않는다. 실행·권한·종료 코드·재부팅·서명 검증 지원을 조사하고 부족한 부분의 구현 경계를 확정한다. | BL-05, BL-23, BL-24, BL-36~39 |
|
||||
| R07 | 중간 | [배포 승인 기준](04-staged-rollout.md)의 관찰 기간·성공률·표본 수는 예시이고 승인 담당자는 미정이다. | 날짜 도달을 승격 승인으로 사용할 수 없다. 분모·취소·미응답·재부팅 대기 처리와 중대 장애 기준을 정하고 실제 테스터 확보를 출시 의존성으로 둔다. | BL-06, BL-38, BL-42, BL-43 |
|
||||
| R08 | 중간 | [서명](06-code-signing-and-smartscreen.md), [Store](05-microsoft-store.md)는 계약·제3자 파일·용량·외부 정책에 의존한다. | 서명 준비는 초반에 시작하되 외부 처리 기간을 개발 완료로 보장하지 않는다. Store는 별도 가능성 판단 후 일정에 추가한다. 단일 파일 출력 불가를 전체 설치 기능 실패와 구분한다. | BL-03, BL-18, BL-19, BL-44, BL-45 |
|
||||
| R09 | 중간 | [시안](../../output/egbim-installer-preview.html)은 설치 사용자의 화면이며 [제작기 화면 목록](../code-design/07-ui-and-commands.md)을 구현한 것이 아니다. | 제작기와 최종 Setup 화면을 별도 항목으로 추적한다. 시안의 성공 상태와 진행률은 실제 측정 결과가 아니며 native 화면·접근성·실패 상태 시험이 남아 있다. | BL-29~33 |
|
||||
| R10 | 중간 | [보존 정책](03-package-and-upload.md)은 지원 기준·패치·복구·Store URL 보존을 요구하지만 기간과 삭제 절차는 미정이다. | 오래된 원본을 정리하면 repair와 후속 패치가 깨질 수 있다. 참조 추적, 보존 만료, 백업 복구 시험을 운영 인수 조건으로 만든다. | BL-04, BL-20, BL-40, BL-43 |
|
||||
| R11 | 높음 | 기존 설계가 EG-BIM 전용으로 읽히고 MSIX를 후속 선택으로 제외했다. | 범용 제작기·두 형식 필수·Store 별도 배포로 정정. 공통/형식별 모델·두 백엔드·검증·일정 v2 반영. | BL-46~53 |
|
||||
|
||||
## 범위 정리
|
||||
|
||||
이전 v2 범위 정정에서는 범용 제작기 완료 범위를 **EXE·MSIX 생성**으로 두었다. 현재 v3는 MSIX 먼저이며 아래 EXE·서버 항목은 후속이다. 장기 계약은 형식별 identity/서명/업데이트, Rust CLI/Tauri 제작 화면, EXE 과정/UI 편집과 MSP, 공통 검증·내보내기다. EG-BIM 실제 전환·기존 업데이터·자체 서버의 4단계 배포는 계획에 유지하되 별도 적용 트랙으로 판정한다. 이 트랙의 외부 자료 부족이 다른 제품의 로컬 패키지 생성을 막지 않는다.
|
||||
|
||||
Store 제출은 검토 범위이며 정식 출시의 공통 차단 조건으로 두지 않는다. 자동 승격, 독자 바이너리 차분 엔진, 모든 과거 버전 조합, 다중 기준 단일 MSP, MSIX 다중 아키텍처 bundle, ISM 자동 가져오기, 복잡한 운영 대시보드는 이번 기준 일정에 포함하지 않는다. 이 항목을 추가하면 범위와 일정을 다시 산정한다.
|
||||
|
||||
## 실행 계획
|
||||
|
||||
[구현 백로그](../backlog/README.md)는 위 발견을 53개 작업으로 구체화한다. [개발 일정과 마일스톤](10-development-schedule.md)은 **AI 지원 없이 단독 개발**하는 기준이며, 제작기·업데이터·서버 작업을 한 사람의 용량 안에서 순차 배치한다. 기존 문서의 단계 목록은 영역별 설계 설명으로 유지하고, 통합 실행 순서와 통과 조건은 이 일정 문서를 기준으로 추적한다.
|
||||
|
||||
외부 승인·테스터 모집·서명 계약의 실제 담당자, 지원 버전 목록, 주당 확보 가능한 시간은 아직 확정되지 않았다. 이 문서는 해당 결정을 대신 승인하지 않는다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# 단독 개발 일정과 마일스톤 — MSIX 우선
|
||||
|
||||
기준선 v3: 2026-10-19, Asia/Seoul. 사용자의 “우선 MSIX를 만들어주는 프로그램” 요청에 따른 재배치다. **개발자 1명, AI 지원 없음**을 유지한다. [설계](../code-design/12-msix-first-builder.md), [백로그](../backlog/README.md), [변경 기록](../changes/2026-10-19-msix-first.md)을 함께 관리한다.
|
||||
|
||||
## 범위와 추정
|
||||
|
||||
첫 버전은 범용 MSIX 프로젝트·파일/manifest·MakeAppx·서명·불변 결과·직접 배포/App Installer·GUI/CLI·Windows VM 검증이다. EXE/MSI/MSP·HTML 설치 마법사·사용자 정의 BA·EG-BIM 전환·자체 인증/그룹 서버·Store 제출·bundle은 후속이다. 기존 53개 작업 중 18개를 1차로 배치하고 35개를 이월한다. 후속 작업을 완료 처리하거나 삭제하지 않는다.
|
||||
|
||||
현재 잠정 예산은 **24주 + 별도 완충 4주**다. 2026-10-26 시작 가정에서 MS6 목표는 **2027-04-09**, 완충 포함 계획 경계는 **2027-05-07**이다. 사용자가 확정한 출시일이나 실측 견적이 아니다. 기존 v2의 W38/2027-07-16 및 W52/2027-10-22 통합 계획은 이 기준선으로 대체한다. 후속 EXE·서버·Store의 새 날짜는 아직 배정하지 않는다.
|
||||
|
||||
MSIX만 먼저 만들므로 기존 52주에서 단순히 8주를 떼어내는 계산을 하지 않는다. 공통 프로젝트/파일/작업/서명/저장소/GUI 기반을 MSIX 경로에서 먼저 구현하는 공수를 포함해 재배치한다. MS0에서 작은 앱의 실제 도구 실험 후 다시 산정한다.
|
||||
|
||||
## 산정 조건
|
||||
|
||||
| 항목 | 기준 |
|
||||
| --- | --- |
|
||||
| 인력 | 개발자 1명이 학습·설계·구현·자체 리뷰·VM/수동 시험·문서·릴리스를 수행. 별도 QA 없음. |
|
||||
| AI | AI 코드 생성·설계·리뷰·테스트·문서화의 시간 단축을 가정하지 않음. 일반 IDE/CI/자동 테스트는 사용. |
|
||||
| 용량 | 전담 주 40시간 중 계획 작업 30시간, 대응·환경 정비·작은 재작업 여유 10시간. 실제 가용 시간 미확정. |
|
||||
| 총 예산 | 24×30 = 약 720 계획 시간. 완충 4주는 별도이며 기능 작업을 숨겨 넣지 않음. |
|
||||
| 작업 순서 | 구현 WIP 1. 엔진·UI·QA가 같은 사람의 시간임을 반영하고 병렬로 계산하지 않음. |
|
||||
| 경험 | Windows 앱 개발 경험을 가정. Rust/Tauri/SDK 경험 부족분은 MS0에서 학습 기간 추가. |
|
||||
| 달력 | 월~금 구간. 야근/주말 제외. 공휴일·휴가·회사 휴무는 착수 시 반영해 완충/목표일 조정. |
|
||||
| 외부 의존성 | Windows VM·실제 서명 접근 확보. Store 계정·EG-BIM 자료·그룹 테스터는 1차 의존성이 아님. |
|
||||
| UI | 두 시안 중 한 가지를 제품 기본 화면으로 선택. 시안이 이미 존재해도 실제 UI/IPC 구현 완료로 계산하지 않음. |
|
||||
|
||||
## 단계별 일정
|
||||
|
||||
| 마일스톤 | 주차 / 기간 | 예산 | 백로그 | 결과와 통과 조건 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| MS0 범위·위험 실험 | W1~3 / 2026-10-26 ~ 2026-11-13 | 3주 | BL-46/02/03/06 | 작은 앱의 MSIX 생성·서명·설치·업데이트와 도구/지원 OS/CPU 조합 확정. 공통화·서명 지연·학습 공수 재산정. |
|
||||
| MS1 공통 엔진·CLI·VM | W4~7 / 2026-11-16 ~ 2026-12-11 | 4주 | BL-09/10/11/14/47/16/41 | MSIX-only v2 모델·입력 스냅샷·작업 수명·backend/CLI·VM 증빙. EXE 설정/도구 없이 동작. |
|
||||
| MS2 MSIX 생성 | W8~11 / 2026-12-14 ~ 2027-01-08 | 4주 | BL-48/49 | manifest·identity·자산·의존성 검증과 MakeAppx pack. 실제 결과 내용 검사, 누락/취소/디스크 부족 시험. |
|
||||
| MS3 서명·결과 보관 | W12~14 / 2027-01-11 ~ 2027-01-29 | 3주 | BL-50 | 개발/운영/미서명 구분, Publisher·신뢰·서명/해시 검사, 불변 결과·로그·증빙·내보내기. |
|
||||
| MS4 직접 배포 업데이트 | W15~17 / 2027-02-01 ~ 2027-02-19 | 3주 | BL-51 | App Installer 설정/URI·버전 검증, 실제 업데이트·중단/재시도·실행 중 앱·데이터 보존. |
|
||||
| MS5 제작기 UI | W18~21 / 2027-02-22 ~ 2027-03-19 | 4주 | BL-29/52 | 선택한 한 가지 레이아웃, 실파일/자산/의존성 편집, 서명·업데이트·진행/실패·접근성. CLI와 같은 결과. |
|
||||
| MS6 MSIX 제품 완료 | W22~24 / 2027-03-22 ~ 2027-04-09 | 3주 | BL-53 | 두 독립 제품의 실제 생성·서명·설치·실행·업데이트·제거, 필수 실패 시험·사용 가이드·증빙 완성. |
|
||||
| 완충 | W25~28 / 2027-04-12 ~ 2027-05-07 | 4주 | 지연된 1차 작업 | 기존 범위의 불확실성/외부 지연에만 사용. EXE·서버·Store 기능을 넣지 않음. |
|
||||
|
||||
MS2는 패키지 생성 중간 결과이며 제품 완료가 아니다. MS3 서명/보관과 MS4 업데이트 증빙, MS5 GUI가 연결된 뒤 MS6 회귀를 통과해야 한다. 미서명 개발 파일 생성이나 HTML 모의 빌드 성공을 실제 설치 가능/출시 완료로 표시하지 않는다.
|
||||
|
||||
## 실행 순서와 통과 조건
|
||||
|
||||
- MS0: 두 독립 가상 제품 선정, 지원 OS/CPU·SDK 고정, Publisher/서명·App Installer 경로 실험. 서명 접근 신청은 즉시 시작하며 발급 대기를 구현 완료로 세지 않는다.
|
||||
- MS1: 프로젝트→파일 스냅샷→작업 엔진→backend 포트→CLI 순서로 연결. VM은 첫 실제 패키지부터 증빙을 수집하도록 준비한다. MSI GUID/레지스트리 컴파일은 구현하지 않는다.
|
||||
- MS2: 단순 앱부터 자산·실행 항목·런타임/의존성을 확장. 미지원 서비스/드라이버/임의 설치 동작은 계획 단계에서 차단한다.
|
||||
- MS3: 공통 Signer/ArtifactRepository를 MSIX 경로에서 구현. Publisher 불일치·신뢰 실패·타임스탬프 오류·중단/재시도·동일 releaseId 덮어쓰기 금지를 검사한다. 운영 서명 미확보 시 배포 준비 게이트는 통과 불가다.
|
||||
- MS4: 실제 HTTPS 시험 호스트로 버전 증가·건너뛰기·다운로드 중단·앱 사용 중 업데이트·데이터 보존을 검사한다. 이 호스트 구성은 시험 예산에 포함하며 자체 장치 인증/4단계 배포 서버 구현으로 확장하지 않는다.
|
||||
- MS5: 한 디자인으로 실제 파일·자산·의존성·서명 프로필·출력 폴더 편집과 작업 이벤트를 연결한다. 제작기 자체 배포/실행도 확인한다. 모의 시안의 즉시 완료 버튼은 실제 제품에 사용하지 않는다.
|
||||
- MS6: 모든 1차 작업의 증빙을 실제 아티팩트 해시에 연결하고 사용 가이드·서명 오류·업데이트/복구 절차를 완성한다. 필수 notRun 항목이 남으면 통과시키지 않는다.
|
||||
|
||||
## 변경과 지연 관리
|
||||
|
||||
매주 완료 ID·증빙·다음 한 작업·차단 원인·잔여 기간을 갱신한다. 1주 이상 지연 전망, 도구/지원 범위 변경, 추가 런타임 요구가 생기면 뒤 날짜와 완충을 함께 수정한다. 실제 계획 시간이 주 30시간보다 작으면 남은 작업 시간을 실제 주당 시간으로 나눠 재산정한다. 외부 서명 대기는 단순 비례 축소하지 않는다.
|
||||
|
||||
MS0·MS2·MS4에서 공수를 다시 산정한다. 시안의 접근성/GUI·CLI 동등성, 실제 서명, 업데이트/제거 시험을 삭제해 날짜를 맞추지 않는다. EXE/HTML 설치 화면/Store 등 후속 요청을 1차에 넣으면 설계·백로그·일정을 함께 변경한다. 사용자 요청 없이 후속 개발 일정을 확정하지 않는다.
|
||||
+14
-7
@@ -1,15 +1,19 @@
|
||||
# EG-BIM 네트워크 설치 및 배포 계획
|
||||
# 범용 설치 패키지 제작 및 배포 계획
|
||||
|
||||
기준일: 2026-10-16, Asia/Seoul. 대상 프로그램: `D:\egbim\repo\14.1`.
|
||||
**현재 기준:** [MSIX 우선 제작기](../code-design/12-msix-first-builder.md)와 [일정 v3](10-development-schedule.md). 이전 EXE/EG-BIM 중심 계획은 후속 적용 자료이며 첫 MSIX 출시의 선행 조건이 아니다.
|
||||
|
||||
EG-BIM의 기존 Windows 설치 구조를 유지하면서 InstallShield를 대체하고, 버전별 패키지 관리와 4단계 그룹 배포를 지원한다. Microsoft Store 배포와 코드 서명도 함께 준비한다.
|
||||
기준일: 2026-10-16, Asia/Seoul. EG-BIM 적용 사례 경로: `D:\egbim\repo\14.1`. 제품 범위는 2026-10-19 정정했다.
|
||||
|
||||
제품은 **범용 Windows 설치 패키지 제작기**이며 현재 첫 버전은 MSIX 출력을 먼저 완성한다. EXE는 후속 단계다. EG-BIM의 InstallShield 전환과 4단계 그룹 배포는 적용·연계 트랙으로 유지한다. [형식과 배포 대상의 분리](../code-design/11-generic-exe-msix-architecture.md)를 전체 계획에 적용한다.
|
||||
|
||||
사용자가 확정한 사항은 Windows 데스크톱 앱 배포, InstallShield 사용 중단, 버전별 패키지 관리와 패치 지원, 업로드 체계, 개발자 테스터부터 일반 사용자까지의 4단계 배포다. Microsoft Store 배포는 검토 대상이다.
|
||||
|
||||
현재 권고안은 **WiX MSI + Burn 전체 설치 EXE + 자체 배포 서버 및 업데이터**다. Store에는 전체 설치 EXE를 등록하는 경로를 우선 검토한다. WiX 채택, Azure 서명 서비스 계약, 세부 운영 기준은 아직 확정되지 않았다.
|
||||
EXE 백엔드는 **WiX MSI + Burn**, MSIX 백엔드는 **Windows SDK MakeAppx**를 사용한다. 자체 배포 서버·업데이터는 별도 연계다. Store에는 제작기가 생성한 EXE 또는 MSIX를 제품 적합성에 따라 등록한다. WiX 채택, Azure 서명 서비스 계약, 세부 운영 기준은 아직 확정되지 않았다.
|
||||
|
||||
## 문서 목록
|
||||
|
||||
실제 등록 절차는 [초보자를 위한 Microsoft Store 배포 매뉴얼](../manuals/microsoft-store/README.md)에서 확인한다.
|
||||
|
||||
생성 프로그램의 구현 설계는 [Rust + Tauri 설계 문서](../code-design/README.md)에 별도로 정리한다. 파일·레지스트리 편집, 버전/GUID, 전체 릴리스·MSP 생성, 대용량 분할 출력과 화면/CLI 계약을 다룬다.
|
||||
|
||||
| 문서 | 내용 |
|
||||
@@ -22,16 +26,19 @@ EG-BIM의 기존 Windows 설치 구조를 유지하면서 InstallShield를 대
|
||||
| [06 코드 서명과 SmartScreen](06-code-signing-and-smartscreen.md) | 서명 대상과 순서, 서비스 비용, 게시자, SmartScreen 한계 |
|
||||
| [07 구현 순서와 검증 계획](07-implementation-and-validation.md) | 선행 결정, 구현 단계, 마이그레이션 및 배포 시험 |
|
||||
| [08 버전별 패치](08-version-patching.md) | 기준 버전별 패치 선택, MSP, 누적 패치, 실패 복구 및 전체 설치 전환 |
|
||||
| [09 계획 검토 결과](09-plan-review.md) | 문서 간 의존성·미확정 사항 검토와 백로그 연결 |
|
||||
| [10 개발 일정과 마일스톤](10-development-schedule.md) | AI 지원 없는 단독 개발 기준 일정, 단계별 통과 조건과 완충 |
|
||||
| [구현 백로그](../backlog/README.md) | 우선순위·선행 조건·완료 기준이 있는 1차 18개·후속 35개 작업 |
|
||||
|
||||
## 설계 원칙
|
||||
|
||||
1. 테스트부터 일반 배포까지 같은 서명 완료 패키지를 사용한다.
|
||||
2. 파일 업로드와 사용자 공개를 별도 상태로 관리한다.
|
||||
3. 기존 설치 경로와 사용자 설정을 보존한다.
|
||||
4. 설치 대상 버전은 서버에서 인증된 사용자·장치와 정책으로 결정한다.
|
||||
3. EXE 기존 설치 전환에서는 경로와 사용자 설정을 보존한다. MSIX 경로는 OS가 관리하며 앱 데이터 이전은 별도 검증한다.
|
||||
4. 자체 그룹 배포를 사용하는 경우 대상 버전은 서버에서 인증된 사용자·장치와 정책으로 결정한다. 로컬 패키지 생성에 서버를 요구하지 않는다.
|
||||
5. 배포 중지, 설치 중 실패 복구, 설치 완료 후 장애 복구를 구분한다.
|
||||
6. 코드 서명과 SmartScreen 평판을 구분한다. Azure 서명도 경고 면제를 보장하지 않는다.
|
||||
7. 버전별 패치를 필수 지원하며, 전체 설치 파일도 함께 유지한다. 적용 가능한 기준 버전과 설치 상태를 검증한 뒤 패치를 실행한다.
|
||||
7. 첫 버전의 MSIX는 버전 증가 패키지와 App Installer로 업데이트한다. EXE/MSI의 전체 설치·MSP는 후속 범위로 유지한다. 적용 가능한 기준 버전과 설치 상태를 검증한 뒤 패치를 실행한다.
|
||||
|
||||
## 검토 범위
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,164 @@
|
||||
<style>
|
||||
#eg-wizard-design { width:100%; }
|
||||
#eg-wizard-design .ew-stage { min-height:690px; }
|
||||
#eg-wizard-design .ew-preview,#eg-wizard-design .ew-app { --ew-bg:light-dark(#ffffff,#20252d); --ew-soft:light-dark(#f4f6f9,#191e26); --ew-line:light-dark(#dce2ea,#3c4553); --ew-ink:light-dark(#202c3d,#edf2fa); --ew-muted:light-dark(#5f6d80,#b0bdce); --ew-blue:light-dark(#2656bd,#a6c0ff); --ew-on:light-dark(#ffffff,#112956); --ew-wash:light-dark(#edf3ff,#293a57); --ew-good:light-dark(#246b50,#94d9b7); --ew-warn:light-dark(#865517,#efc280); --ew-bad:light-dark(#a63532,#ffb0ac); color:var(--ew-ink); font:14px/1.6 'Segoe UI','Malgun Gothic',sans-serif; }
|
||||
#eg-wizard-design * { box-sizing:border-box; }
|
||||
#eg-wizard-design .ew-preview { display:flex; flex-wrap:wrap; align-items:flex-end; gap:8px; padding:14px 0; padding-right:92px; }
|
||||
#eg-wizard-design .ew-preview label { display:grid; gap:4px; font-size:11px; color:var(--ew-muted); }
|
||||
#eg-wizard-design .ew-preview select { max-width:100%; background:var(--ew-bg); color:var(--ew-ink); border:1px solid var(--ew-line); border-radius:5px; padding:6px 8px; font:12px/1.5 'Segoe UI','Malgun Gothic',sans-serif; }
|
||||
#eg-wizard-design button { font:500 12px/1.5 'Segoe UI','Malgun Gothic',sans-serif; }
|
||||
#eg-wizard-design .ew-button { display:inline-flex; justify-content:center; align-items:center; gap:7px; min-height:34px; padding:7px 16px; border:1px solid var(--ew-line); border-radius:5px; color:var(--ew-ink); background:var(--ew-bg); }
|
||||
#eg-wizard-design button:disabled { opacity:.48; cursor:not-allowed; }
|
||||
#eg-wizard-design .ew-primary { background:var(--ew-blue); color:var(--ew-on); border-color:var(--ew-blue); }
|
||||
#eg-wizard-design .ew-link { background:transparent; border:0; color:var(--ew-blue); padding:5px 0; }
|
||||
#eg-wizard-design .ew-app { background:var(--ew-bg); border:1px solid var(--ew-line); border-radius:9px; overflow-wrap:anywhere; box-shadow:0 8px 30px light-dark(#17305710,#00000025); }
|
||||
#eg-wizard-design .ew-title { min-height:44px; display:flex; gap:9px; align-items:center; padding:10px 18px; border-bottom:1px solid var(--ew-line); font-size:12px; }
|
||||
#eg-wizard-design .ew-mark { display:grid; place-items:center; width:23px; height:23px; background:var(--ew-blue); color:var(--ew-on); border-radius:5px; font-weight:600; flex-shrink:0; }
|
||||
#eg-wizard-design .ew-tag { margin-left:auto; font-size:11px; color:var(--ew-muted); }
|
||||
#eg-wizard-design .ew-layout { display:grid; grid-template-columns:154px minmax(0,1fr); min-height:480px; }
|
||||
#eg-wizard-design .ew-side { background:var(--ew-soft); padding:28px 18px; border-right:1px solid var(--ew-line); }
|
||||
#eg-wizard-design .ew-side-brand { font-size:17px; font-weight:600; letter-spacing:-.6px; margin-bottom:4px; }
|
||||
#eg-wizard-design .ew-side-sub { color:var(--ew-muted); font-size:11px; }
|
||||
#eg-wizard-design .ew-steps { list-style:none; display:grid; gap:21px; margin:34px 0 0; padding:0; }
|
||||
#eg-wizard-design .ew-steps li { display:flex; align-items:center; gap:9px; color:var(--ew-muted); font-size:12px; }
|
||||
#eg-wizard-design .ew-number { display:grid; place-items:center; width:22px; height:22px; border:1px solid var(--ew-line); border-radius:50%; font-size:11px; flex-shrink:0; }
|
||||
#eg-wizard-design .ew-steps [aria-current=step] { color:var(--ew-blue); font-weight:600; }
|
||||
#eg-wizard-design .ew-steps [aria-current=step] .ew-number { background:var(--ew-blue); color:var(--ew-on); border-color:transparent; }
|
||||
#eg-wizard-design .ew-past .ew-number { color:var(--ew-good); }
|
||||
#eg-wizard-design .ew-main { min-width:0; }
|
||||
#eg-wizard-design .ew-page-heading { padding:23px 26px 18px; border-bottom:1px solid var(--ew-line); }
|
||||
#eg-wizard-design .ew-page-heading h2 { margin:0 0 5px; font-size:19px; font-weight:600; letter-spacing:-.6px; }
|
||||
#eg-wizard-design .ew-page-heading p { margin:0; color:var(--ew-muted); font-size:12px; }
|
||||
#eg-wizard-design .ew-body { padding:22px 26px; }
|
||||
#eg-wizard-design .ew-body h3 { font-size:15px; margin:0 0 10px; font-weight:600; }
|
||||
#eg-wizard-design .ew-body p { margin:0 0 14px; font-size:13px; }
|
||||
#eg-wizard-design .ew-muted { color:var(--ew-muted); }
|
||||
#eg-wizard-design .ew-small { font-size:11px !important; }
|
||||
#eg-wizard-design .ew-box { padding:14px 16px; border:1px solid var(--ew-line); border-radius:6px; margin:14px 0; background:var(--ew-bg); }
|
||||
#eg-wizard-design .ew-box-top { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; margin-bottom:7px; }
|
||||
#eg-wizard-design .ew-chip { display:inline-block; color:var(--ew-good); background:var(--ew-soft); font-size:11px; padding:2px 7px; border-radius:4px; }
|
||||
#eg-wizard-design .ew-path { display:block; font-size:12px; color:var(--ew-muted); overflow-wrap:anywhere; }
|
||||
#eg-wizard-design .ew-note { display:flex; align-items:flex-start; gap:9px; padding:12px; background:var(--ew-wash); color:var(--ew-blue); border-radius:5px; font-size:12px; margin-top:14px; }
|
||||
#eg-wizard-design .ew-note svg { flex-shrink:0; margin-top:2px; }
|
||||
#eg-wizard-design .ew-list { padding:0; margin:0; list-style:none; }
|
||||
#eg-wizard-design .ew-list li { display:flex; justify-content:space-between; gap:12px; padding:9px 0; font-size:12px; border-bottom:1px solid var(--ew-line); }
|
||||
#eg-wizard-design .ew-list li:last-child { border:0; }
|
||||
#eg-wizard-design .ew-good { color:var(--ew-good); }
|
||||
#eg-wizard-design .ew-bad { color:var(--ew-bad); }
|
||||
#eg-wizard-design .ew-status { font-size:11px; white-space:nowrap; }
|
||||
#eg-wizard-design .ew-field { display:grid; gap:6px; font-size:12px; margin:0 0 16px; }
|
||||
#eg-wizard-design .ew-field input { width:100%; border:1px solid var(--ew-line); border-radius:5px; padding:9px 10px; background:var(--ew-bg); color:var(--ew-ink); font:12px/1.5 'Segoe UI','Malgun Gothic',sans-serif; }
|
||||
#eg-wizard-design .ew-choice { display:flex; align-items:flex-start; gap:8px; padding:9px 0; font-size:12px; }
|
||||
#eg-wizard-design .ew-choice input { accent-color:var(--ew-blue); margin:3px 0 0; flex-shrink:0; }
|
||||
#eg-wizard-design .ew-choice span { display:block; }
|
||||
#eg-wizard-design .ew-choice small { display:block; color:var(--ew-muted); font-size:11px; margin-top:2px; }
|
||||
#eg-wizard-design .ew-rule { height:1px; background:var(--ew-line); margin:14px 0; }
|
||||
#eg-wizard-design .ew-summary { display:grid; grid-template-columns:88px minmax(0,1fr); gap:10px 14px; font-size:12px; margin:0; }
|
||||
#eg-wizard-design .ew-summary dt { color:var(--ew-muted); }
|
||||
#eg-wizard-design .ew-summary dd { margin:0; }
|
||||
#eg-wizard-design .ew-progress { background:var(--ew-soft); height:8px; border-radius:4px; overflow:hidden; margin:18px 0 7px; }
|
||||
#eg-wizard-design .ew-progress span { display:block; background:var(--ew-blue); height:100%; }
|
||||
#eg-wizard-design .ew-progress-label { display:flex; justify-content:space-between; gap:12px; color:var(--ew-muted); font-size:12px; margin-bottom:15px; }
|
||||
#eg-wizard-design .ew-footer { border-top:1px solid var(--ew-line); background:var(--ew-soft); padding:14px 18px; border-radius:0 0 9px 9px; display:flex; justify-content:space-between; align-items:center; gap:10px; flex-wrap:wrap; }
|
||||
#eg-wizard-design .ew-footer-label { color:var(--ew-muted); font-size:11px; }
|
||||
#eg-wizard-design .ew-actions { display:flex; gap:7px; flex-wrap:wrap; margin-left:auto; }
|
||||
#eg-wizard-design .ew-symbol { display:grid; place-items:center; width:42px; height:42px; border-radius:50%; background:var(--ew-wash); color:var(--ew-blue); font-size:23px; margin:0 0 15px; }
|
||||
#eg-wizard-design .ew-log { margin-top:16px; color:var(--ew-muted); font-size:11px; }
|
||||
#eg-wizard-design .ew-log summary { width:fit-content; }
|
||||
#eg-wizard-design .ew-log pre { white-space:pre-wrap; overflow-wrap:anywhere; font:11px/1.7 'Segoe UI','Malgun Gothic',sans-serif; }
|
||||
#eg-wizard-design .ew-confirm { background:var(--ew-bg); border:1px solid var(--ew-line); border-radius:6px; padding:16px; margin-top:16px; }
|
||||
#eg-wizard-design .ew-confirm .ew-actions { margin-top:12px; }
|
||||
#eg-wizard-design .ew-compact .ew-layout { display:block; }
|
||||
#eg-wizard-design .ew-compact .ew-side { display:none; }
|
||||
#eg-wizard-design .ew-compact .ew-page-heading { padding-left:30px; padding-right:30px; background:var(--ew-soft); }
|
||||
#eg-wizard-design .ew-compact .ew-body { max-width:610px; padding:24px 30px; margin:auto; }
|
||||
#eg-wizard-design .ew-caption { color:var(--ew-muted); font-size:11px; margin:10px 0 0; }
|
||||
@media(max-width:580px) { #eg-wizard-design .ew-stage { min-height:850px; } #eg-wizard-design .ew-layout { display:block; } #eg-wizard-design .ew-side { padding:12px 16px; border-right:0; border-bottom:1px solid var(--ew-line); } #eg-wizard-design .ew-side-brand,#eg-wizard-design .ew-side-sub { display:none; } #eg-wizard-design .ew-steps { display:flex; gap:7px; justify-content:space-between; margin:0; } #eg-wizard-design .ew-steps li { flex-direction:column; gap:5px; font-size:11px; } #eg-wizard-design .ew-page-heading,#eg-wizard-design .ew-compact .ew-page-heading { padding:18px; } #eg-wizard-design .ew-body,#eg-wizard-design .ew-compact .ew-body { padding:18px; } #eg-wizard-design .ew-preview { padding-right:0; padding-top:55px; } #eg-wizard-design .ew-title { padding:10px 14px; } #eg-wizard-design .ew-summary { grid-template-columns:70px minmax(0,1fr); } }
|
||||
@media(pointer:coarse) { #eg-wizard-design button,#eg-wizard-design select,#eg-wizard-design .ew-choice { min-height:44px; } #eg-wizard-design .ew-field input { font-size:16px; } }
|
||||
</style>
|
||||
<div id="eg-wizard-design" class="viz-carousel viz-dotted-background" aria-label="EG-BIM 설치 마법사 재디자인" data-previous-label="이전 디자인" data-next-label="다음 디자인">
|
||||
<section data-variant="진행 안내형" class="ew-stage" aria-label="진행 안내형 설치 마법사"><div id="ew-guided-tools" class="ew-preview"></div><div id="ew-guided" class="ew-app" aria-label="진행 안내형"></div></section>
|
||||
<section data-variant="표준 마법사형" class="ew-stage" aria-label="표준 마법사형 설치 마법사" hidden><div id="ew-standard-tools" class="ew-preview"></div><div id="ew-standard" class="ew-app ew-compact" aria-label="표준 마법사형"></div></section>
|
||||
</div>
|
||||
<script>
|
||||
(() => {
|
||||
const root=document.getElementById('eg-wizard-design');
|
||||
const escape=v=>String(v).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
const modes={new:'신규 설치',upgrade:'기존 버전 전환',patch:'버전 패치',repair:'설치 복구',remove:'제거'};
|
||||
const scenarios={normal:'정상 완료',backupFail:'백업 실패',applyFail:'설치 실패',reboot:'재부팅 필요',locked:'실행 중인 앱'};
|
||||
const actions={new:'설치',upgrade:'업데이트',patch:'패치 적용',repair:'복구',remove:'제거'};
|
||||
const basePath='C:\\Program Files\\Baron\\EG-BIM', legacyPath='D:\\Baron\\EG-BIM';
|
||||
const defaults=()=>({mode:'upgrade',scenario:'normal',page:'welcome',agreed:false,path:basePath,resources:true,shortcut:true,removeConfirmed:false,launch:true,restart:false,confirmCancel:false,cancelled:false,error:'',closed:false});
|
||||
function sequence(s) { return s.mode==='new'?['welcome','license','options','review','prepare','apply','finish']:['welcome','review','prepare','apply','finish']; }
|
||||
function normalize(input) { const s=defaults(); if(!input||typeof input!=='object')return s; for(const key of Object.keys(s)){if(typeof input[key]===typeof s[key])s[key]=input[key];} if(!modes[s.mode])s.mode='upgrade';if(!scenarios[s.scenario])s.scenario='normal';if(![...sequence(s),'failed','cancelled'].includes(s.page))s.page='welcome'; if(s.scenario==='backupFail'&&!['upgrade','patch'].includes(s.mode))s.scenario='normal';return s; }
|
||||
const saved=window.openai?.widgetState?.privateContent?.wizards||{};
|
||||
const states={'ew-guided':normalize(saved['ew-guided']),'ew-standard':normalize(saved['ew-standard'])};
|
||||
function next(s) {
|
||||
s.error='';
|
||||
if(s.page==='license'&&!s.agreed){s.error='사용권 계약에 동의해야 다음 단계로 이동할 수 있습니다.';return;}
|
||||
if(s.page==='options'&&!/^[a-zA-Z]:\\[^<>:"|?*\r\n]+$/.test(s.path)){s.error='드라이브를 포함한 설치 경로를 입력해 주세요. 예: C:\\Program Files\\Baron\\EG-BIM';return;}
|
||||
if(s.page==='review'&&s.mode==='remove'&&!s.removeConfirmed){s.error='제거할 항목을 확인하고 동의해 주세요.';return;}
|
||||
const seq=sequence(s),index=seq.indexOf(s.page); if(index>=0&&index<seq.length-1)s.page=seq[index+1];
|
||||
}
|
||||
function simulate(s) {
|
||||
if(s.confirmCancel)return;
|
||||
if(s.page==='prepare') {
|
||||
if(s.scenario==='locked'){s.error='EG-BIM에서 도면을 저장하고 종료한 후 다시 확인해 주세요.';return;}
|
||||
s.page=s.scenario==='backupFail'?'failed':'apply';
|
||||
} else if(s.page==='apply')s.page=s.cancelled||s.scenario==='applyFail'?'failed':'finish';
|
||||
}
|
||||
function row(label,value,tone='') {return `<li><span>${label}</span><span class="ew-status ${tone}">${value}</span></li>`;}
|
||||
function note(text,icon='shield-check') {return `<div class="ew-note"><i data-lucide="${icon}" aria-hidden="true"></i><span>${text}</span></div>`;}
|
||||
function choice(label,key,checked,sub='',disabled=false) {return `<label class="ew-choice"><input type="checkbox" data-value="${key}" ${checked?'checked':''} ${disabled?'disabled':''}><span>${label}${sub?`<small>${sub}</small>`:''}</span></label>`;}
|
||||
function title(s) {
|
||||
const a=actions[s.mode];
|
||||
return {welcome:[s.mode==='new'?'EG-BIM 설치를 시작합니다':s.mode==='upgrade'?'기존 EG-BIM을 업데이트합니다':s.mode==='patch'?'새 버전의 변경 사항을 적용합니다':s.mode==='repair'?'EG-BIM 설치를 복구합니다':'EG-BIM을 제거합니다','계속하려면 내용을 확인하고 다음을 선택하세요.'],license:['사용권 계약','설치하기 전에 사용권 계약을 확인해 주세요.'],options:['설치 위치 및 옵션','설치할 위치와 추가 항목을 선택하세요.'],review:[`${a} 준비가 되었습니다`,'아래 내용을 확인하세요. 이전 단계로 돌아가 선택을 바꿀 수 있습니다.'],prepare:['설치 환경을 준비하고 있습니다','작업을 저장하고 실행 중인 EG-BIM을 종료해 주세요.'],apply:[s.cancelled?'취소 요청을 처리하고 있습니다':`${a} 작업을 진행하고 있습니다`,s.cancelled?'안전한 중단 지점과 현재 설치 상태를 확인합니다.':'작업이 끝날 때까지 PC를 끄지 마세요.'],finish:[s.scenario==='reboot'?'완료하려면 PC를 다시 시작해야 합니다':`${a} 작업이 완료되었습니다`,s.scenario==='reboot'?'열려 있는 작업을 저장한 후 다시 시작해 주세요.':'아래 내용을 확인하고 마침을 선택하세요.'],failed:[s.scenario==='backupFail'?'설정 백업을 완료하지 못했습니다':s.cancelled?'작업을 중단했습니다':'설치를 완료하지 못했습니다',s.scenario==='backupFail'?'기존 제품을 변경하지 않았습니다.':'현재 상태를 확인한 후 복구 절차를 진행해야 합니다.'],cancelled:['설치를 취소했습니다','프로그램을 변경하기 전에 종료했습니다.']}[s.page];
|
||||
}
|
||||
function body(s) {
|
||||
const a=actions[s.mode], existing=s.mode!=='new', backup=['upgrade','patch'].includes(s.mode), path=existing?legacyPath:s.path;
|
||||
if(s.page==='welcome')return `<div class="ew-symbol"><i data-lucide="${s.mode==='remove'?'package-minus':s.mode==='repair'?'wrench':'package-check'}" aria-hidden="true"></i></div><h3>${s.mode==='new'?'설계에 필요한 도구를 준비하세요.':s.mode==='upgrade'?'작업 환경은 유지하고, 프로그램은 새롭게.':s.mode==='patch'?'설치된 구성은 그대로 유지합니다.':s.mode==='repair'?'프로그램 파일과 설치 정보를 복구합니다.':'프로그램과 설치 항목을 제거합니다.'}</h3><p class="ew-muted">${s.mode==='remove'?'개인 도면, 사용자 설정과 보관된 백업은 유지합니다.':s.mode==='new'?'마법사의 안내에 따라 설치 위치와 옵션을 선택할 수 있습니다.':'작업 중인 도면을 저장한 후 진행해 주세요.'}</p><div class="ew-box"><div class="ew-box-top"><strong>EG-BIM</strong><span class="ew-chip">${existing?'기존 설치 확인':'Windows · x64'}</span></div><span class="ew-path">${escape(path)}</span><span class="ew-small ew-muted">${existing?'기존 설치 위치를 그대로 사용합니다.':'기본 설치 위치 · 다음 단계에서 변경 가능'}</span></div>${note(backup?'설정 백업을 확인한 후 프로그램 변경을 시작합니다.':s.mode==='remove'?'타사 CAD 연결과 사용자 데이터는 삭제 대상에서 제외합니다.':'시스템 변경이 필요한 경우 Windows가 관리자 권한을 요청합니다.')}`;
|
||||
if(s.page==='license')return `<div class="ew-box"><h3>EG-BIM 소프트웨어 사용권 계약</h3><p class="ew-muted">설치 화면 검토용 약관 자리표시자입니다.</p><p class="ew-small ew-muted">실제 설치 파일에는 제품 담당자가 승인한 약관 전문과 버전을 표시합니다. 이 시안의 선택은 법적 계약 동의나 실제 설치를 수행하지 않습니다.</p></div>${choice('사용권 계약에 동의합니다.','agreed',s.agreed)}${note('동의 여부는 설치 시작 전까지 변경할 수 있습니다.','info')}`;
|
||||
if(s.page==='options')return `<label class="ew-field">설치 위치<input data-path aria-label="설치 위치" value="${escape(s.path)}" spellcheck="false"></label><h3>설치 구성</h3>${choice('EG-BIM 프로그램','core',true,'필수 구성요소',true)}${choice('추가 리소스','resources',s.resources,'기능 선택 예시 · 실제 리소스 목록은 별도 확정')}<div class="ew-rule"></div>${choice('바탕 화면에 바로가기 만들기','shortcut',s.shortcut)}<p class="ew-small ew-muted">기존 CAD 파일 연결은 자동으로 변경하지 않습니다.</p>`;
|
||||
if(s.page==='review')return `<dl class="ew-summary"><dt>작업</dt><dd>${modes[s.mode]}</dd><dt>${s.mode==='remove'?'제거 위치':'설치 위치'}</dt><dd>${escape(path)}${existing&&s.mode!=='remove'?' · 유지':''}</dd><dt>설치 구성</dt><dd>${s.mode==='remove'?'현재 설치된 프로그램 제거':existing?'현재 설치된 기능 유지':s.resources?'프로그램 + 추가 리소스':'프로그램'}</dd><dt>사용자 데이터</dt><dd>${backup?'설정·CUI·추가 리소스 백업 후 호환 설정 복원':s.mode==='remove'?'개인 도면·설정·백업 유지':'기존 데이터 유지'}</dd>${s.mode==='new'?`<dt>바로가기</dt><dd>${s.shortcut?'바탕 화면에 생성':'생성 안 함'}</dd>`:''}<dt>필수 구성</dt><dd>${s.mode==='remove'?'공유 런타임 유지':'필요한 런타임만 준비'}</dd></dl>${s.mode==='remove'?choice('프로그램을 제거하고 개인 데이터는 유지합니다.','removeConfirmed',s.removeConfirmed):note(backup?'파일 확보와 백업 검증에 실패하면 기존 제품을 제거하지 않습니다.':'설치 전 패키지와 저장 공간을 다시 확인합니다.')}<details class="ew-log"><summary class="cursor-interaction">예정 작업 자세히 보기</summary><p>환경 검사 → 파일 검증 → ${backup?'앱 종료 확인 · 설정 백업 → ':''}${a} → 상태 확인${backup?' · 설정 복원':''}</p></details>`;
|
||||
if(s.page==='prepare')return `<ul class="ew-list">${row('지원 환경 · 저장 공간','확인 완료','ew-good')}${row('설치 파일 · 서명 · 무결성','확인 완료','ew-good')}${row('실행 중인 프로그램',s.scenario==='locked'?'EG-BIM 실행 중':'종료 확인',s.scenario==='locked'?'ew-bad':'ew-good')}${backup?row('사용자 설정 백업',s.scenario==='locked'?'대기':'검사 중'):row('실행 계획 준비','준비 중')}</ul>${s.scenario==='locked'?`${note('도면을 직접 저장하고 EG-BIM을 종료해 주세요. 강제 종료하지 않습니다.','info')}<button type="button" class="ew-button cursor-interaction" data-action="recheck" style="margin-top:12px">다시 확인</button>`:note(backup?'백업 위치: D:\\EG-BIM-Backup\\시도-001 (예시)':'현재까지 프로그램 파일은 변경하지 않았습니다.')}<p class="ew-small ew-muted" style="margin-top:16px">시안 진행은 창 위의 ‘작업 진행’으로 확인할 수 있습니다.</p>`;
|
||||
if(s.page==='apply')return `<h3>${s.cancelled?'안전한 중단 지점 확인 중':s.mode==='remove'?'등록된 프로그램 파일 제거 중':'프로그램 파일 적용 중'}</h3><div class="ew-progress" role="progressbar" aria-label="진행률 예시" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64"><span style="width:64%"></span></div><div class="ew-progress-label"><span>${s.cancelled?'취소 요청됨':'현재 작업 진행률'}</span><span>64%</span></div><ul class="ew-list">${row('환경 및 설치 파일 확인','완료','ew-good')}${backup?row('사용자 설정 백업 검증','완료','ew-good'):''}${row(a,s.cancelled?'중단 요청 처리 중':'진행 중')}${row('설치 상태 확인','대기')}</ul><details class="ew-log"><summary class="cursor-interaction">작업 내역 보기</summary><pre>시도: DEMO-001\n환경 검사: 완료\n패키지 검증: 완료\n${backup?'백업 검증: 완료\n':''}작업 상태: ${s.cancelled?'취소 처리 중':'적용 중'}\n이 내역은 시안용 예시입니다.</pre></details>`;
|
||||
if(s.page==='failed')return `<div class="ew-symbol">!</div><h3>${s.scenario==='backupFail'?'백업 저장 위치를 확인해 주세요.':'진단 기록을 보관해 주세요.'}</h3><p class="ew-muted">${s.scenario==='backupFail'?'백업 위치의 공간 또는 쓰기 권한을 확인한 후 다시 검사할 수 있습니다.':'현재 설치 상태가 확인되지 않았습니다. 설치 파일을 다시 실행하거나 전체 설치로 덮어쓰기 전에 복구 상태를 확인해야 합니다.'}</p><ul class="ew-list">${row('프로그램 상태',s.scenario==='backupFail'?'기존 상태 유지':'확인 필요',s.scenario==='backupFail'?'ew-good':'ew-bad')}${row('백업',backup?(s.scenario==='backupFail'?'검증되지 않음':'보관됨'):'해당 없음')}${row('다음 조치',s.scenario==='backupFail'?'백업 위치 확인':'진단 및 복구')}</ul><details class="ew-log" open><summary class="cursor-interaction">진단 기록</summary><pre>시도: DEMO-001\n상태: ${s.scenario==='backupFail'?'BackupValidationFailed':s.cancelled?'CancellationStateUncertain':'InstallStateUncertain'}\n로그: 설치 로그 보관 위치 (예시)\n이 시안은 실제 시스템 상태를 조회하지 않습니다.</pre></details>`;
|
||||
if(s.page==='cancelled')return `<div class="ew-symbol">−</div><h3>다음에 다시 시작할 수 있습니다.</h3><p class="ew-muted">설치 전 취소되어 기존 프로그램과 사용자 데이터는 유지됩니다.</p>`;
|
||||
const reboot=s.scenario==='reboot';
|
||||
return `<div class="ew-symbol">${reboot?'↻':'✓'}</div><ul class="ew-list">${row(a,'완료','ew-good')}${backup?row('호환 설정 복원','완료','ew-good'):''}${row('설치 상태',reboot?'재부팅 후 확인':'확인 완료',reboot?'':'ew-good')}</ul>${reboot?`${choice('지금 다시 시작','restart',s.restart,'선택하지 않으면 나중에 직접 재부팅합니다.')}<p class="ew-small ew-muted">시안에서는 실제 재부팅하지 않습니다.</p>`:s.mode!=='remove'?choice('마침 후 EG-BIM 실행','launch',s.launch,'원래 사용자 권한으로 실행'):'<p class="ew-small ew-muted" style="margin-top:15px">개인 도면·사용자 설정·백업은 유지됩니다.</p>'}${backup?note('백업은 유지됩니다. 도면·출력·인증·플러그인을 확인한 후 정리하세요.'):''}${s.closed?'<p class="ew-small ew-muted" role="status" style="margin-top:12px">미리보기를 마쳤습니다. 실제 실행이나 재부팅은 하지 않았습니다.</p>':''}`;
|
||||
}
|
||||
function persist(id) {window.openai?.setWidgetState?.({modelContent:{design:id==='ew-guided'?'진행 안내형':'표준 마법사형',mode:states[id].mode,page:states[id].page,scenario:states[id].scenario},privateContent:{wizards:states}})?.catch(()=>{});}
|
||||
function render(id,focus=false) {
|
||||
const s=states[id],app=document.getElementById(id),tools=document.getElementById(id+'-tools');
|
||||
tools.innerHTML=`<label>시안 · 설치 상황<select class="cursor-interaction" data-mode aria-label="시안 설치 상황">${Object.entries(modes).map(([k,v])=>`<option value="${k}" ${s.mode===k?'selected':''}>${v}</option>`).join('')}</select></label><label>시험할 상태<select class="cursor-interaction" data-scenario aria-label="시험할 상태">${Object.entries(scenarios).filter(([k])=>k!=='backupFail'||['upgrade','patch'].includes(s.mode)).map(([k,v])=>`<option value="${k}" ${s.scenario===k?'selected':''}>${v}</option>`).join('')}</select></label><button class="ew-button cursor-interaction" data-demo="advance" ${!['prepare','apply'].includes(s.page)||s.confirmCancel?'disabled':''}>작업 진행</button><button class="ew-button cursor-interaction" data-demo="reset">처음부터</button>`;
|
||||
tools.querySelector('[data-mode]').addEventListener('change',e=>{states[id]=defaults();states[id].mode=e.target.value;render(id);persist(id);});
|
||||
tools.querySelector('[data-scenario]').addEventListener('change',e=>{s.scenario=e.target.value;s.page='welcome';s.error='';s.cancelled=false;s.confirmCancel=false;s.closed=false;render(id);persist(id);});
|
||||
tools.querySelector('[data-demo=advance]').addEventListener('click',()=>{simulate(s);render(id);persist(id);});
|
||||
tools.querySelector('[data-demo=reset]').addEventListener('click',()=>{states[id]={...defaults(),mode:s.mode,scenario:s.scenario};render(id);persist(id);});
|
||||
const [heading,sub]=title(s),seq=sequence(s),index=seq.indexOf(s.page);
|
||||
const groups=s.mode==='new'?['시작','선택','확인','진행','완료']:['시작','확인','진행','완료'];
|
||||
const current=(s.mode==='new'?{welcome:0,license:1,options:1,review:2,prepare:3,apply:3,finish:4,failed:3,cancelled:0}:{welcome:0,review:1,prepare:2,apply:2,finish:3,failed:2,cancelled:0})[s.page];
|
||||
const busy=['prepare','apply'].includes(s.page),end=['finish','failed','cancelled'].includes(s.page);
|
||||
const button= end?(s.page==='failed'&&s.scenario==='backupFail'?'다시 검사':s.page==='finish'?'마침':'닫기'):s.page==='review'?`${actions[s.mode]} 시작`:busy?s.cancelled?'취소 처리 중…':'진행 중…':'다음';
|
||||
app.innerHTML=`<header class="ew-title"><span class="ew-mark">E</span><span>EG-BIM 설치 마법사</span><span class="ew-tag">${modes[s.mode]}</span></header><div class="ew-layout"><aside class="ew-side"><div class="ew-side-brand">EG-BIM</div><div class="ew-side-sub">BARON SOFTWARE</div><ol class="ew-steps">${groups.map((n,i)=>`<li ${i===current?'aria-current="step"':''} class="${i<current?'ew-past':''}"><span class="ew-number">${i<current?'✓':i+1}</span>${n}</li>`).join('')}</ol></aside><main class="ew-main"><header class="ew-page-heading"><h2>${heading}</h2><p>${sub}</p></header><div class="ew-body"><div aria-live="polite">${body(s)}</div>${s.error?`<p class="ew-small ew-bad" role="alert">${escape(s.error)}</p>`:''}${s.confirmCancel?`<section class="ew-confirm" aria-label="취소 확인"><h3>작업을 취소하시겠습니까?</h3><p class="ew-small ew-muted">${s.page==='apply'?'안전한 중단 지점까지 기다린 후 설치 상태를 확인합니다.':'아직 프로그램을 변경하지 않았습니다.'}</p><div class="ew-actions"><button class="ew-button cursor-interaction" data-action="keep">계속 진행</button><button class="ew-button cursor-interaction" data-action="confirm">취소 요청</button></div></section>`:''}</div></main></div><footer class="ew-footer"><span class="ew-footer-label">시안 · 표시 정보는 예시</span><div class="ew-actions"><button class="ew-button cursor-interaction" data-action="back" ${index<=0||busy||end||s.confirmCancel?'disabled':''}>이전</button><button class="ew-button ew-primary cursor-interaction" data-action="next" ${busy||s.confirmCancel||s.page==='license'&&!s.agreed||s.page==='review'&&s.mode==='remove'&&!s.removeConfirmed?'disabled':''}>${button}</button>${!end?`<button class="ew-button cursor-interaction" data-action="cancel" ${s.cancelled||s.confirmCancel?'disabled':''}>취소</button>`:''}</div></footer>`;
|
||||
app.querySelector('[data-path]')?.addEventListener('input',e=>{s.path=e.target.value;});
|
||||
app.querySelectorAll('[data-value]').forEach(el=>el.addEventListener('change',e=>{s[el.dataset.value]=e.target.checked;render(id);persist(id);app.querySelector(`[data-value="${el.dataset.value}"]`)?.focus({preventScroll:true});}));
|
||||
app.querySelector('[data-action=back]').addEventListener('click',()=>{if(index>0&&!busy&&!end){s.page=seq[index-1];s.error='';render(id,true);persist(id);}});
|
||||
app.querySelector('[data-action=next]').addEventListener('click',()=>{
|
||||
if(s.page==='failed'&&s.scenario==='backupFail'){s.scenario='normal';s.page='prepare';}
|
||||
else if(end){s.closed=true;if(s.page!=='finish'){s.page='welcome';s.cancelled=false;s.closed=false;}}
|
||||
else next(s);
|
||||
render(id,true);persist(id);
|
||||
});
|
||||
app.querySelector('[data-action=cancel]')?.addEventListener('click',()=>{s.confirmCancel=true;render(id);app.querySelector('[data-action=keep]')?.focus({preventScroll:true});});
|
||||
app.querySelector('[data-action=keep]')?.addEventListener('click',()=>{s.confirmCancel=false;render(id,true);});
|
||||
app.querySelector('[data-action=confirm]')?.addEventListener('click',()=>{s.confirmCancel=false;if(s.page==='apply')s.cancelled=true;else s.page='cancelled';render(id,true);persist(id);});
|
||||
app.querySelector('[data-action=recheck]')?.addEventListener('click',()=>{s.scenario='normal';s.error='';render(id);persist(id);});
|
||||
if(globalThis.lucide)lucide.createIcons({attrs:{width:16,height:16}});
|
||||
if(focus&&!busy)app.querySelector('[data-action=next]')?.focus({preventScroll:true});
|
||||
}
|
||||
Object.keys(states).forEach(id=>render(id));
|
||||
window.addEventListener('openai:set_globals',e=>{const restored=e.detail?.globals?.widgetState?.privateContent?.wizards;if(restored)Object.keys(states).forEach(id=>{states[id]=normalize(restored[id]);render(id);});});
|
||||
if(globalThis.Tweak)Object.keys(states).forEach(id=>{const app=document.getElementById(id),design={radius:9};const tweak=new Tweak({container:app,onChange:()=>{app.style.borderRadius=design.radius+'px';}});tweak.addSlider(design,'radius',{label:'창 모서리',min:0,max:16,unit:'px'});});
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,177 @@
|
||||
<div id="msix-builder-concept">
|
||||
<style>
|
||||
#msix-builder-concept { font-family: "Segoe UI", "Malgun Gothic", sans-serif; color-scheme: light dark; }
|
||||
#msix-builder-concept * { box-sizing: border-box; }
|
||||
#msix-builder-concept [hidden] { display: none !important; }
|
||||
#msix-builder-concept .ms-app { --ms-bg: light-dark(#f6f7fa,#171b23); --ms-paper: light-dark(#ffffff,#202630); --ms-text: light-dark(#202a39,#edf1f8); --ms-muted: light-dark(#59677b,#aebacf); --ms-line: light-dark(#dce2eb,#3a4353); --ms-accent: light-dark(#245bd7,#96b7ff); --ms-soft: light-dark(#edf3ff,#273752); --ms-button: light-dark(#245bd7,#a9c3ff); --ms-onbutton: light-dark(#ffffff,#152445); --ms-good: light-dark(#17654c,#8bd7b6); --ms-warn: light-dark(#805011,#edc27e); --ms-error: light-dark(#a52c33,#ffabb0); color:var(--ms-text); background:var(--ms-bg); border:1px solid var(--ms-line); border-radius:12px; overflow:hidden; min-height:940px; display:flex; flex-direction:column; font-size:14px; line-height:1.55; }
|
||||
#msix-builder-concept button, #msix-builder-concept input, #msix-builder-concept select { font:inherit; }
|
||||
#msix-builder-concept button { color:inherit; cursor:inherit; }
|
||||
#msix-builder-concept .ms-top { display:flex; align-items:center; gap:12px; padding:16px 22px; padding-right:104px; border-bottom:1px solid var(--ms-line); background:var(--ms-paper); flex-wrap:wrap; }
|
||||
#msix-builder-concept .ms-brand { font-size:16px; font-weight:600; display:flex; gap:10px; align-items:center; }
|
||||
#msix-builder-concept .ms-mark { display:grid; place-items:center; width:32px; height:32px; border-radius:9px; background:var(--ms-button); color:var(--ms-onbutton); }
|
||||
#msix-builder-concept .ms-pill { padding:3px 9px; border-radius:5px; background:var(--ms-soft); color:var(--ms-accent); font-size:12px; }
|
||||
#msix-builder-concept .ms-caption { color:var(--ms-muted); font-size:12px; }
|
||||
#msix-builder-concept .ms-spacer { flex:1; }
|
||||
#msix-builder-concept .ms-layout { flex:1; display:grid; grid-template-columns:190px minmax(0,1fr); }
|
||||
#msix-builder-concept .ms-nav { padding:23px 12px; border-right:1px solid var(--ms-line); }
|
||||
#msix-builder-concept .ms-project { padding:0 12px 23px; overflow-wrap:anywhere; }
|
||||
#msix-builder-concept .ms-project strong { display:block; font-weight:600; margin:4px 0; }
|
||||
#msix-builder-concept .ms-nav button { display:flex; align-items:center; gap:11px; width:100%; border:0; background:transparent; padding:11px 12px; text-align:left; border-radius:7px; margin-bottom:5px; }
|
||||
#msix-builder-concept .ms-nav button[aria-current="step"] { background:var(--ms-soft); color:var(--ms-accent); font-weight:600; }
|
||||
#msix-builder-concept .ms-nav svg { flex:none; }
|
||||
#msix-builder-concept .ms-nav .ms-nav-end { margin:30px 12px 0; padding-top:15px; border-top:1px solid var(--ms-line); }
|
||||
#msix-builder-concept .ms-content { min-width:0; padding:27px 28px 20px; }
|
||||
#msix-builder-concept h2 { margin:5px 0 7px; font-size:25px; line-height:1.35; font-weight:600; letter-spacing:-.6px; }
|
||||
#msix-builder-concept h3 { margin:0 0 17px; font-size:15px; font-weight:600; }
|
||||
#msix-builder-concept p { margin:0; }
|
||||
#msix-builder-concept .ms-eyebrow { font-size:11px; letter-spacing:1.4px; font-weight:600; color:var(--ms-accent); }
|
||||
#msix-builder-concept .ms-lead { color:var(--ms-muted); margin-bottom:25px; }
|
||||
#msix-builder-concept .ms-cols { display:grid; grid-template-columns:minmax(0,1.65fr) minmax(190px,1fr); gap:20px; align-items:start; }
|
||||
#msix-builder-concept .ms-panel { background:var(--ms-paper); border:1px solid var(--ms-line); border-radius:10px; padding:20px; min-width:0; }
|
||||
#msix-builder-concept .ms-fields { display:grid; grid-template-columns:1fr 1fr; gap:17px; }
|
||||
#msix-builder-concept .ms-full { grid-column:1/-1; }
|
||||
#msix-builder-concept label.ms-field { display:flex; flex-direction:column; gap:6px; font-size:12px; font-weight:600; }
|
||||
#msix-builder-concept input:not([type="checkbox"]), #msix-builder-concept select { width:100%; min-width:0; padding:9px 10px; border:1px solid var(--ms-line); border-radius:6px; color:var(--ms-text); background:var(--ms-paper); font-weight:400; }
|
||||
#msix-builder-concept input:focus-visible, #msix-builder-concept select:focus-visible, #msix-builder-concept button:focus-visible { outline:2px solid var(--ms-accent); outline-offset:3px; }
|
||||
#msix-builder-concept .ms-field small { color:var(--ms-muted); font-size:11px; font-weight:400; }
|
||||
#msix-builder-concept .ms-line { height:1px; background:var(--ms-line); margin:20px 0; }
|
||||
#msix-builder-concept .ms-note { margin-top:16px; padding:12px 14px; background:var(--ms-soft); border-radius:6px; color:var(--ms-muted); font-size:12px; }
|
||||
#msix-builder-concept .ms-appicon { display:grid; place-items:center; width:56px; height:56px; border-radius:13px; background:var(--ms-button); color:var(--ms-onbutton); margin-bottom:17px; }
|
||||
#msix-builder-concept .ms-appicon svg { width:27px; height:27px; }
|
||||
#msix-builder-concept .ms-preview-name { font-size:19px; font-weight:600; overflow-wrap:anywhere; margin-bottom:4px; }
|
||||
#msix-builder-concept .ms-preview-description { font-size:12px; color:var(--ms-muted); min-height:38px; overflow-wrap:anywhere; }
|
||||
#msix-builder-concept .ms-kv { display:flex; align-items:flex-start; gap:14px; justify-content:space-between; font-size:12px; padding:8px 0; }
|
||||
#msix-builder-concept .ms-kv span:first-child { color:var(--ms-muted); flex-shrink:0; }
|
||||
#msix-builder-concept .ms-kv span:last-child { overflow-wrap:anywhere; text-align:right; min-width:0; }
|
||||
#msix-builder-concept .ms-button { display:inline-flex; justify-content:center; align-items:center; gap:7px; background:var(--ms-paper); border:1px solid var(--ms-line); border-radius:6px; padding:9px 14px; font-weight:500; min-height:39px; }
|
||||
#msix-builder-concept .ms-button.primary { background:var(--ms-button); border-color:transparent; color:var(--ms-onbutton); }
|
||||
#msix-builder-concept .ms-button:disabled { opacity:.5; cursor:not-allowed; }
|
||||
#msix-builder-concept .ms-button.full { width:100%; margin-top:14px; }
|
||||
#msix-builder-concept .ms-footer { display:flex; gap:12px; justify-content:space-between; align-items:center; margin-top:24px; flex-wrap:wrap; }
|
||||
#msix-builder-concept .ms-actions { display:flex; gap:8px; flex-wrap:wrap; }
|
||||
#msix-builder-concept .ms-status { font-size:12px; color:var(--ms-muted); }
|
||||
#msix-builder-concept .ms-check { display:flex; gap:10px; align-items:flex-start; margin:13px 0; }
|
||||
#msix-builder-concept input[type="checkbox"] { width:17px; height:17px; accent-color:var(--ms-accent); margin:3px 0 0; flex:none; }
|
||||
#msix-builder-concept .ms-check small { display:block; font-size:12px; color:var(--ms-muted); margin-top:3px; }
|
||||
#msix-builder-concept .ms-toolbar { display:flex; justify-content:space-between; gap:10px; align-items:center; margin-bottom:16px; flex-wrap:wrap; }
|
||||
#msix-builder-concept .ms-toolbar h3 { margin:0; }
|
||||
#msix-builder-concept .ms-file { display:flex; align-items:center; gap:11px; padding:13px 0; border-bottom:1px solid var(--ms-line); min-width:0; }
|
||||
#msix-builder-concept .ms-file:last-child { border-bottom:0; }
|
||||
#msix-builder-concept .ms-file .ms-filename { flex:1; min-width:0; overflow-wrap:anywhere; }
|
||||
#msix-builder-concept .ms-file small { display:block; color:var(--ms-muted); font-size:11px; }
|
||||
#msix-builder-concept .ms-file > span:last-child { font-size:12px; color:var(--ms-muted); white-space:nowrap; }
|
||||
#msix-builder-concept .ms-file svg { color:var(--ms-muted); flex:none; }
|
||||
#msix-builder-concept .ms-choice { display:flex; align-items:center; gap:10px; padding:14px; border:1px solid var(--ms-line); border-radius:7px; margin-bottom:10px; }
|
||||
#msix-builder-concept .ms-choice.active { border-color:var(--ms-accent); background:var(--ms-soft); }
|
||||
#msix-builder-concept .ms-choice strong { display:block; font-size:13px; font-weight:600; }
|
||||
#msix-builder-concept .ms-choice small { color:var(--ms-muted); font-size:12px; }
|
||||
#msix-builder-concept .ms-good { color:var(--ms-good); }
|
||||
#msix-builder-concept .ms-warn { color:var(--ms-warn); }
|
||||
#msix-builder-concept .ms-error { color:var(--ms-error); }
|
||||
#msix-builder-concept .ms-alert { padding:13px 15px; border:1px solid var(--ms-line); border-left:3px solid var(--ms-error); background:var(--ms-paper); border-radius:6px; margin-bottom:17px; font-size:12px; }
|
||||
#msix-builder-concept .ms-alert button { margin-top:10px; }
|
||||
#msix-builder-concept .ms-stage { display:flex; align-items:flex-start; gap:12px; padding:14px 0; border-bottom:1px solid var(--ms-line); }
|
||||
#msix-builder-concept .ms-stage:last-child { border:0; }
|
||||
#msix-builder-concept .ms-stage .ms-stage-title { flex:1; min-width:0; }
|
||||
#msix-builder-concept .ms-stage small { display:block; color:var(--ms-muted); font-size:12px; }
|
||||
#msix-builder-concept .ms-stage > span:last-child { font-size:12px; }
|
||||
#msix-builder-concept .ms-meter { height:6px; border-radius:4px; background:var(--ms-line); overflow:hidden; margin:12px 0; }
|
||||
#msix-builder-concept .ms-meter div { height:100%; background:var(--ms-accent); }
|
||||
#msix-builder-concept .ms-code { font:12px/1.8 Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; color:var(--ms-muted); margin:0; }
|
||||
#msix-builder-concept .ms-bottom { display:flex; gap:10px; justify-content:space-between; padding:11px 22px; border-top:1px solid var(--ms-line); background:var(--ms-paper); flex-wrap:wrap; font-size:11px; color:var(--ms-muted); }
|
||||
#msix-builder-concept .ms-steps { display:grid; grid-template-columns:repeat(6,1fr); gap:8px; padding:22px 26px 0; }
|
||||
#msix-builder-concept .ms-steps button { border:0; background:transparent; padding:8px 0; display:flex; flex-direction:column; align-items:center; gap:7px; color:var(--ms-muted); font-size:12px; }
|
||||
#msix-builder-concept .ms-step-dot { width:27px; height:27px; border:1px solid var(--ms-line); border-radius:50%; display:grid; place-items:center; background:var(--ms-paper); font-size:12px; }
|
||||
#msix-builder-concept .ms-steps button[aria-current="step"] { color:var(--ms-accent); }
|
||||
#msix-builder-concept .ms-steps button[aria-current="step"] .ms-step-dot { background:var(--ms-button); color:var(--ms-onbutton); border-color:transparent; }
|
||||
#msix-builder-concept .ms-guided .ms-content { flex:1; padding:24px 40px; }
|
||||
#msix-builder-concept .ms-guided .ms-cols { grid-template-columns:minmax(0,1.6fr) minmax(210px,1fr); }
|
||||
#msix-builder-concept .ms-guided { --ms-accent:light-dark(#146d60,#82d7c6); --ms-soft:light-dark(#eaf5f2,#263e3a); --ms-button:light-dark(#146d60,#9ae1d2); --ms-onbutton:light-dark(#ffffff,#14332e); }
|
||||
@media(max-width:800px) { #msix-builder-concept .ms-layout { grid-template-columns:154px minmax(0,1fr); } #msix-builder-concept .ms-content { padding:22px 18px; } #msix-builder-concept .ms-cols, #msix-builder-concept .ms-guided .ms-cols { grid-template-columns:1fr; } #msix-builder-concept .ms-side { display:grid; grid-template-columns:1fr 1fr; gap:16px; } #msix-builder-concept .ms-side > .ms-caption { grid-column:1/-1; } #msix-builder-concept .ms-guided .ms-content { padding:22px; } }
|
||||
@media(max-width:520px) { #msix-builder-concept .ms-app { min-height:1900px; } #msix-builder-concept .ms-layout { grid-template-columns:1fr; } #msix-builder-concept .ms-nav { border-right:0; border-bottom:1px solid var(--ms-line); padding:12px; display:grid; grid-template-columns:1fr 1fr; gap:3px; } #msix-builder-concept .ms-project, #msix-builder-concept .ms-nav-end { display:none; } #msix-builder-concept .ms-nav button { padding:8px; margin:0; font-size:12px; } #msix-builder-concept .ms-fields, #msix-builder-concept .ms-side { grid-template-columns:1fr; } #msix-builder-concept .ms-top { padding:14px 16px; padding-right:96px; } #msix-builder-concept .ms-top .ms-caption { display:none; } #msix-builder-concept .ms-content, #msix-builder-concept .ms-guided .ms-content { padding:20px 14px; } #msix-builder-concept .ms-panel { padding:16px; } #msix-builder-concept .ms-steps { padding:12px; grid-template-columns:repeat(3,1fr); } #msix-builder-concept .ms-footer { align-items:stretch; } #msix-builder-concept .ms-actions { flex:1; justify-content:flex-end; } #msix-builder-concept .ms-bottom { padding:10px 14px; } }
|
||||
@media(pointer:coarse) { #msix-builder-concept .ms-button, #msix-builder-concept .ms-nav button, #msix-builder-concept .ms-steps button { min-height:44px; } #msix-builder-concept input:not([type="checkbox"]), #msix-builder-concept select { font-size:16px; } }
|
||||
</style>
|
||||
<div class="viz-carousel" aria-label="MSIX 제작기 디자인" data-previous-label="이전 시안" data-next-label="다음 시안">
|
||||
<section data-variant="프로젝트 작업실" aria-label="프로젝트 작업실">
|
||||
<div class="ms-app" data-app="studio"></div>
|
||||
</section>
|
||||
<section data-variant="단계별 제작" aria-label="단계별 제작" hidden>
|
||||
<div class="ms-app ms-guided" data-app="guided"></div>
|
||||
</section>
|
||||
</div>
|
||||
<script>
|
||||
(() => {
|
||||
const root = document.getElementById('msix-builder-concept');
|
||||
const pages = [['app','앱 정보','panels-top-left'],['files','파일 구성','folder-open'],['manifest','패키지 설정','package'],['sign','서명','shield-check'],['update','업데이트','refresh-cw'],['build','검증 · 빌드','hammer']];
|
||||
const defaults = () => ({page:'app',name:'Orbit Notes',description:'팀의 아이디어를 한곳에',publisherName:'Example Studio',identity:'ExampleStudio.OrbitNotes',publisher:'CN=Example Studio',version:'1.2.0.0',arch:'x64',exe:'OrbitNotes.exe',minOs:'10.0.19041.0',sign:'development',certSubject:'CN=Example Studio',autoUpdate:false,url:'https://downloads.example.com/orbit/stable/OrbitNotes.appinstaller',interval:'24',prompt:true,extraFile:false,revision:1,validated:false,build:'idle',log:false,message:'',error:''});
|
||||
const state = {studio:defaults(),guided:defaults()};
|
||||
const sessionId = Date.now().toString(36) + Math.random().toString(36).slice(2);
|
||||
const esc = v => String(v).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
const icon = name => `<i data-lucide="${name}" aria-hidden="true"></i>`;
|
||||
const field = (s,key,label,full=false,hint='') => `<label class="ms-field ${full?'ms-full':''}">${label}<input data-field="${key}" value="${esc(s[key])}" ${key==='url'?'type="url"':'type="text"'}>${hint?`<small>${hint}</small>`:''}</label>`;
|
||||
const select = (s,key,label,opts) => `<label class="ms-field">${label}<select data-field="${key}">${opts.map(([v,l])=>`<option value="${v}" ${s[key]===v?'selected':''}>${l}</option>`).join('')}</select></label>`;
|
||||
const check = (s,key,label,hint='') => `<label class="ms-check"><input type="checkbox" data-field="${key}" ${s[key]?'checked':''}><span>${label}${hint?`<small>${hint}</small>`:''}</span></label>`;
|
||||
const kv=(a,b)=>`<div class="ms-kv"><span>${a}</span><span>${b}</span></div>`;
|
||||
function validate(s) {
|
||||
if(!s.name.trim()||!s.identity.trim()||!s.publisher.trim()) return ['app','제품 이름과 패키지 식별 정보를 입력해 주세요.'];
|
||||
if(!/^\d+\.\d+\.\d+\.\d+$/.test(s.version)||s.version.split('.').some(n=>Number(n)>65535)||Number(s.version.split('.')[0])===0) return ['app','버전을 1.2.0.0처럼 네 부분 숫자로 입력해 주세요.'];
|
||||
if(!['OrbitNotes.exe'].includes(s.exe)) return ['files','실행 파일이 패키지 목록에 없습니다. OrbitNotes.exe를 지정해 주세요.'];
|
||||
if(s.sign!=='none' && s.publisher!==s.certSubject) return ['sign','Publisher와 인증서 Subject가 일치하지 않습니다.'];
|
||||
if(s.autoUpdate) { try { const u=new URL(s.url); if(u.protocol!=='https:'||!u.pathname.endsWith('.appinstaller')) throw Error(); } catch { return ['update','HTTPS 주소와 .appinstaller 파일 이름을 확인해 주세요.']; } }
|
||||
return null;
|
||||
}
|
||||
function restore(saved) {
|
||||
if(!saved||saved.schema!==1)return;
|
||||
['studio','guided'].forEach(k=>{
|
||||
const d=defaults(), v=saved[k];if(!v||typeof v!=='object')return;
|
||||
Object.keys(d).forEach(f=>{if(typeof v[f]===typeof d[f]&&(!['string'].includes(typeof v[f])||v[f].length<1000))d[f]=v[f];});
|
||||
if(!pages.some(p=>p[0]===d.page))d.page='app';
|
||||
if(!['development','production','none'].includes(d.sign))d.sign='development';
|
||||
d.validated=false;d.build='idle';d.error='';d.message='';state[k]=d;
|
||||
});
|
||||
}
|
||||
restore(window.openai?.widgetState?.privateContent);
|
||||
function persist(){ const host=window.openai;if(host?.setWidgetState)host.setWidgetState({modelContent:{design:'MSIX-first builder',studioPage:state.studio.page,guidedPage:state.guided.page},privateContent:{schema:1,sessionId,...state}}).catch(()=>{}); }
|
||||
function preview(s) {
|
||||
return `<aside class="ms-side"><div class="ms-panel"><h3>앱 표시 미리보기</h3><div class="ms-appicon">${icon('notebook-pen')}</div><div class="ms-preview-name">${esc(s.name||'앱 이름')}</div><p class="ms-preview-description">${esc(s.description)}</p><div class="ms-line"></div>${kv('게시자',esc(s.publisherName))}${kv('버전',esc(s.version))}${kv('아키텍처',esc(s.arch))}${kv('설치 위치','Windows에서 관리')}<div class="ms-note">설치 폴더 선택 없이 패키지로 배포합니다.</div></div><p class="ms-caption" style="margin-top:12px">표시 정보 예시입니다. 실제 App Installer 화면은 Windows 환경에 따라 달라집니다.</p></aside>`;
|
||||
}
|
||||
function side(s,title,body){return `<aside class="ms-side"><div class="ms-panel"><h3>${title}</h3>${body}</div></aside>`;}
|
||||
function pane(s) {
|
||||
if(s.page==='app')return `<div class="ms-cols"><div class="ms-panel"><h3>사용자에게 표시할 정보</h3><div class="ms-fields">${field(s,'name','앱 이름',true)}${field(s,'description','설명',true)}${field(s,'publisherName','게시자 표시명',true)}${field(s,'version','패키지 버전',false,'네 부분 숫자 버전')}${select(s,'arch','아키텍처',[['x64','x64'],['arm64','ARM64']])}</div><div class="ms-line"></div><div class="ms-toolbar"><span>앱 아이콘</span><span class="ms-caption">Assets / Logo.png · 예시</span></div><p class="ms-caption">실제 제품에서는 로고 파일과 크기를 검사합니다.</p></div>${preview(s)}</div>`;
|
||||
if(s.page==='files')return `<div class="ms-cols"><div class="ms-panel"><div class="ms-toolbar"><h3>패키지에 포함할 파일</h3><button class="ms-button cursor-interaction" data-action="add-file">${icon(s.extraFile?'minus':'plus')}${s.extraFile?'예제 파일 제거':'예제 파일 추가'}</button></div><p class="ms-caption">소스 폴더 · D:\\releases\\orbit-notes</p>${[['OrbitNotes.exe','앱 실행 파일','18.4 MB'],['Orbit.Core.dll','애플리케이션 라이브러리','6.2 MB'],['Assets/Logo.png','앱 이미지 · 예시','24 KB'],['Resources/ko-KR.json','한국어 리소스','12 KB'],...(s.extraFile?[['Resources/en-US.json','추가한 예제 파일','10 KB']]:[])].map(([n,d,z])=>`<div class="ms-file">${icon(n.endsWith('exe')?'file-code':'file')}<div class="ms-filename">${esc(n)}<small>${d}</small></div><span>${z}</span></div>`).join('')}<div class="ms-line"></div>${field(s,'exe','실행 파일',true,'패키지 내부 상대 경로')}</div>${side(s,'파일 구성 원칙',`${kv('포함 파일',`${s.extraFile?5:4}개 · 예시`)}${kv('배치 위치','패키지 내부')}${kv('원본 파일','변경하지 않음')}<div class="ms-note">문서·설정·로그는 앱 데이터 위치를 사용합니다. 설치 폴더 쓰기에 의존하는 앱은 호환성을 확인해야 합니다.</div>`)}</div>`;
|
||||
if(s.page==='manifest')return `<div class="ms-cols"><div class="ms-panel"><h3>패키지 식별 정보</h3><div class="ms-fields">${field(s,'identity','패키지 이름 · Identity Name',true)}${field(s,'publisher','Publisher',true,'서명 인증서의 Subject와 일치해야 합니다.')}${select(s,'minOs','최소 Windows 버전',[['10.0.19041.0','Windows 10 · 2004 이상'],['10.0.22000.0','Windows 11 이상']])}</div><div class="ms-line"></div><h3>앱 실행 방식</h3><div class="ms-choice active">${icon('monitor')}<div><strong>일반 데스크톱 앱</strong><small>Windows.FullTrustApplication</small></div></div><p class="ms-caption">runFullTrust 선언을 포함합니다. 서비스·드라이버·임의 설치 작업은 초기 지원 범위에 포함하지 않습니다.</p></div>${side(s,'생성할 manifest',`<pre class="ms-code"><Identity\n Name="${esc(s.identity)}"\n Publisher="${esc(s.publisher)}"\n Version="${esc(s.version)}"\n ProcessorArchitecture="${esc(s.arch)}" /></pre><div class="ms-note">미리보기는 요약입니다. 실제 생성 시 SDK 스키마·자산·의존성을 함께 검사합니다.</div>`)}</div>`;
|
||||
if(s.page==='sign')return `<div class="ms-cols"><div class="ms-panel"><h3>서명 프로필</h3>${select(s,'sign','사용할 프로필',[['development','개발용 인증서 · 예시'],['production','운영 서명 프로필 · 예시'],['none','미서명 개발 빌드']])}<div class="ms-line"></div>${s.sign==='none'?'<p class="ms-warn">미서명 패키지는 직접 배포 준비 상태가 될 수 없습니다.</p>':`${field(s,'certSubject','인증서 Subject · 예시',true)}<div class="ms-line"></div>${kv('패키지 Publisher',esc(s.publisher))}${kv('이름 일치',s.publisher===s.certSubject?'<span class="ms-good">일치</span>':'<span class="ms-error">불일치</span>')}`}<div class="ms-note">개인 키나 인증서 암호를 프로젝트에 저장하지 않습니다. 실제 제품에서는 OS 또는 서명 서비스 프로필을 참조합니다.</div></div>${side(s,'배포 전 확인',`<div class="ms-stage">${icon('shield-check')}<div class="ms-stage-title">패키지 서명<small>서명자·체인·타임스탬프 검사</small></div></div><div class="ms-stage">${icon('monitor-check')}<div class="ms-stage-title">대상 PC 신뢰<small>개발용 인증서 성공과 구분</small></div></div><div class="ms-note">이 시안은 인증서 저장소에 접근하거나 서명하지 않습니다.</div>`)}</div>`;
|
||||
if(s.page==='update')return `<div class="ms-cols"><div class="ms-panel"><h3>직접 배포</h3><div class="ms-choice active">${icon('globe')}<div><strong>내 서버에서 배포</strong><small>Store 계정 없이 MSIX를 전달합니다.</small></div></div>${check(s,'autoUpdate','App Installer 업데이트 사용','MSIX와 함께 .appinstaller 파일을 생성합니다.')}${s.autoUpdate?`<div class="ms-line"></div><div class="ms-fields">${field(s,'url','업데이트 안내 파일 주소',true,'패키지 파일은 버전별 고정 URL을 사용합니다.')}${select(s,'interval','실행 시 확인 간격',[['0','앱 실행마다'],['24','24시간'],['48','48시간']])}</div>${check(s,'prompt','업데이트 안내 표시')}`:'<div class="ms-note">MSIX 파일을 직접 전달합니다. 자동 업데이트 경로는 연결되지 않습니다.</div>'}</div>${side(s,'생성할 결과',`${kv('설치 패키지','.msix')}${kv('업데이트 안내',s.autoUpdate?'.appinstaller':'사용 안 함')}${kv('업데이트 적용','Windows 배포 기능')}<div class="ms-note">새 버전 전체 패키지를 생성합니다. Windows의 차등 업데이트를 이용하며 별도 MSP 파일을 만들지 않습니다.</div><p class="ms-caption" style="margin-top:14px">Store 등록·자동 업로드·그룹 배포 서버는 후속 단계입니다.</p>`)}</div>`;
|
||||
const completed=s.build==='done',failed=s.build==='failed',ready=s.validated;
|
||||
const stages=[['설정과 파일 검사','manifest · 입력 · 경로','list-checks'],['MSIX 패키징','Windows SDK · MakeAppx','package'],['서명과 무결성',s.sign==='none'?'미서명 개발 결과':'서명 프로필 · 해시','shield-check'],['결과 보관','불변 아티팩트 · 검증 보고서','archive']];
|
||||
return `<div class="ms-cols"><div class="ms-panel"><div class="ms-toolbar"><h3>빌드 계획</h3><span class="ms-pill">${completed?'모의 빌드 완료':failed?'검증 오류':ready?'모의 검사 통과':'검사 대기'}</span></div>${stages.map(([t,d,i],n)=>`<div class="ms-stage">${icon(completed?'circle-check':i)}<div class="ms-stage-title">${t}<small>${d}</small></div><span class="${completed?'ms-good':'ms-caption'}">${completed?(s.sign==='none'&&n===2?'서명 생략':'모의 완료'):'대기'}</span></div>`).join('')}<div class="ms-meter" role="progressbar" aria-label="모의 빌드 진행" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${completed?100:0}"><div style="width:${completed?100:0}%"></div></div><div class="ms-actions"><button class="ms-button cursor-interaction" data-action="validate">설정 검사</button><button class="ms-button primary cursor-interaction" data-action="build">${icon('play')}모의 빌드</button></div>${completed?`<div class="ms-line"></div><h3>결과 예시</h3><pre class="ms-code">OrbitNotes_${esc(s.version)}_${esc(s.arch)}.msix\n${s.autoUpdate?'OrbitNotes.appinstaller\n':''}release.json\nvalidation-report.json</pre><button class="ms-button cursor-interaction" data-action="log" style="margin-top:14px">${s.log?'기록 닫기':'모의 기록 보기'}</button>${s.log?'<pre class="ms-code" style="margin-top:12px">[예시] 입력 스냅샷 고정\n[예시] MakeAppx 단계 완료\n[예시] 서명 정책 적용\n[예시] 결과 목록 생성\n실제 명령 실행 및 파일 생성 없음</pre>':''}`:''}</div>${side(s,'릴리스 준비 상태',`${kv('패키지 생성',completed?'모의 완료':'대기')}${kv('서명',s.sign==='none'?'생략':completed?'모의 완료':'대기')}${kv('설치·실행 시험','미실행')}${kv('업데이트·제거 시험','미실행')}<div class="ms-note">${s.sign==='development'?'개발용 인증서로 설정되어 있습니다. 실제 사용자 배포에는 대상 PC 신뢰와 설치 시험이 필요합니다.':'빌드와 배포 준비는 별도 상태입니다. 실제 VM 검증 증빙이 필요합니다.'}</div>`)}</div>`;
|
||||
}
|
||||
const descriptions={app:'앱 이름과 버전을 입력하면 패키지 표시 정보를 미리 확인할 수 있습니다.',files:'배포할 파일을 모으고 앱의 실행 파일을 지정합니다.',manifest:'Windows가 앱을 식별할 이름과 실행 조건을 설정합니다.',sign:'패키지 게시자와 서명 프로필을 연결합니다.',update:'MSIX만 전달하거나, 내 서버를 통한 업데이트 경로를 연결합니다.',build:'생성 전 설정을 검사하고 패키지와 검증 결과를 확인합니다.'};
|
||||
function render(k) {
|
||||
const app=root.querySelector(`[data-app="${k}"]`),s=state[k],idx=pages.findIndex(p=>p[0]===s.page);
|
||||
const nav=pages.map(([id,label,ic],n)=>`<button class="cursor-interaction" data-page="${id}" ${s.page===id?'aria-current="step"':''}>${k==='guided'?`<span class="ms-step-dot">${n+1}</span>`:icon(ic)}<span>${label}</span></button>`).join('');
|
||||
const error=s.error?`<div class="ms-alert" role="alert">${esc(s.error)}${s.errorPage?`<br><button class="ms-button cursor-interaction" data-page="${esc(s.errorPage)}">해당 설정으로 이동</button>`:''}</div>`:'';
|
||||
app.innerHTML=`<header class="ms-top"><div class="ms-brand"><span class="ms-mark">${icon('package')}</span>MSIX Studio</div><span class="ms-pill">디자인 시안</span><span class="ms-spacer"></span><span class="ms-caption">직접 배포용 패키지 제작</span></header>${k==='guided'?`<nav class="ms-steps" aria-label="제작 단계">${nav}</nav>`:'<div class="ms-layout">'+`<nav class="ms-nav" aria-label="프로젝트 설정"><div class="ms-project"><span class="ms-caption">현재 프로젝트</span><strong>${esc(s.name)}</strong><span class="ms-pill">MSIX · ${esc(s.arch)}</span></div>${nav}<div class="ms-nav-end ms-caption">Windows 패키지 제작<br>단일 제품 · 단일 아키텍처</div></nav>`}<main class="ms-content"><div class="ms-eyebrow">${k==='guided'?`STEP ${idx+1} OF 6`:'PACKAGE WORKSPACE'}</div><h2>${pages[idx][1]}</h2><p class="ms-lead">${descriptions[s.page]}</p>${error}${pane(s)}<footer class="ms-footer"><div class="ms-status" role="status" aria-live="polite">${esc(s.message||'예제 데이터 · 실제 파일 접근 없음')}</div><div class="ms-actions">${idx>0?'<button class="ms-button cursor-interaction" data-action="prev">이전</button>':''}${idx<5?'<button class="ms-button primary cursor-interaction" data-action="next">다음 단계 '+icon('arrow-right')+'</button>':''}</div></footer></main>${k==='studio'?'</div>':''}<div class="ms-bottom"><span>프로젝트 변경 ${s.revision} · ${esc(s.version)}</span><span>실제 패키지 생성·서명·설치 없음</span></div>`;
|
||||
if(globalThis.lucide)globalThis.lucide.createIcons({attrs:{width:16,height:16}});
|
||||
}
|
||||
function runValidation(s){const err=validate(s);s.error=err?err[1]:'';s.errorPage=err?err[0]:'';s.validated=!err;s.message=err?'설정을 수정한 후 다시 검사해 주세요.':'모의 설정 검사 통과 · SDK와 실제 파일 검사는 미실행';return !err;}
|
||||
root.addEventListener('click',e=>{
|
||||
const b=e.target.closest('button'),app=e.target.closest('[data-app]');if(!b||!app)return;const k=app.dataset.app,s=state[k];
|
||||
if(b.dataset.page){s.page=b.dataset.page;s.error='';s.errorPage='';}
|
||||
const a=b.dataset.action,idx=pages.findIndex(p=>p[0]===s.page);
|
||||
if(a==='next'||a==='prev'){s.page=pages[Math.max(0,Math.min(5,idx+(a==='next'?1:-1)))][0];s.error='';s.errorPage='';}
|
||||
if(a==='add-file'){s.extraFile=!s.extraFile;s.revision++;s.validated=false;s.build='idle';s.message=s.extraFile?'예제 파일을 추가했습니다.':'추가한 예제 파일을 제거했습니다.';}
|
||||
if(a==='validate')runValidation(s);
|
||||
if(a==='build'){s.build=runValidation(s)?'done':'failed';if(s.build==='done')s.message='모의 빌드 완료 · 실제 산출물과 설치 증빙은 없습니다.';}
|
||||
if(a==='log')s.log=!s.log;
|
||||
render(k);persist();
|
||||
});
|
||||
root.addEventListener('change',e=>{
|
||||
const f=e.target.dataset.field,app=e.target.closest('[data-app]');if(!f||!app)return;const k=app.dataset.app,s=state[k];s[f]=e.target.type==='checkbox'?e.target.checked:e.target.value;s.revision++;s.validated=false;s.build='idle';s.error='';s.errorPage='';s.message='설정이 변경되었습니다. 빌드 전 다시 검사합니다.';render(k);persist();
|
||||
});
|
||||
window.addEventListener('openai:set_globals',e=>{const saved=e.detail?.globals?.widgetState?.privateContent;if(!saved||saved.schema!==1||saved.sessionId===sessionId)return;restore(saved);render('studio');render('guided');});
|
||||
render('studio');render('guided');
|
||||
if(globalThis.Tweak){['studio','guided'].forEach(k=>{const app=root.querySelector(`[data-app="${k}"]`),design={corners:12};const tweak=new Tweak({container:app,onChange:()=>{app.style.borderRadius=design.corners+'px';}});tweak.addSlider(design,'corners',{label:'창 모서리',min:0,max:20,step:2,unit:'px'});});}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user