# UX UI 출력 패턴 (Output Patterns)

> **작성일**: 2026-04-24
> **위치**: `product/uxui/OUTPUT-PATTERNS.md`
> **범위**: Fricle 워크스페이스 안 모든 앱·도구의 UI 출력 분류 + 결정 가이드. 트레이 앱, 설정, 메뉴바, 캔버스 컨텐츠 등 횡단 적용.

---

## 0. 목적

- 트레이 앱 / 설정 / 도구가 사용자에게 **어떤 형태로 화면에 나타나는지** 5종 패턴으로 정의
- 새 앱·도구 등록 시 **어느 패턴을 선택할지 결정 기준** 제공
- 인프라(컴포넌트 wrapper, AppKit API) 와의 매핑 명시
- "비슷한 도구가 다르게 나타나는" UX 불일치 방지

## 1. 5 출력 + 1 액션 매트릭스

```
              일시 (잠깐)        상시 (지속)
조회/편집     팝업              핀보드 (인스턴스 / 위젯)
무거움        모달              (해당 없음 — 모달은 짧게)
토글만        즉시 액션          —
```

**축**:
- **사용 시점** — 일시 (열고 닫음) vs 상시 (계속 떠있음)
- **작업 깊이** — 조회/편집 / 무거움 (긴 작업) / 토글만

**핀보드 = 인프라 1개 + 표현 패턴 2종** (인스턴스 / 위젯).

본체 / 데이터 / 리사이즈 / 이동 / 액션 / 수치 = 동일하다.

차이는 별도 wrapper 신설이 아니라, 컴포넌트가 `mode === 'pin'` 일 때 위젯 전용 UI 분기를 가지는지 여부다.

총 패턴 = **5 출력 + 1 액션** = 6 패턴.

---

## 2. 패턴별 정의

### 2.1 즉시 액션 (no UI)

| 항목 | 값 |
|---|---|
| 컨테이너 | 없음 |
| 사용 시점 | 토글 1개로 끝나는 동작 |
| 닫힘 트리거 | — |
| 사용자 시각 | 클릭 즉시 상태 변화 (아이콘 모양 / 영역 표시 등) |
| 예시 | 메뉴바 visibility 토글, 히든 영역 》/《 토글, ⠿ 드래그 |

### 2.2 팝업 (Popup)

| 항목 | 값 |
|---|---|
| 컨테이너 | 메뉴바 아이콘 앵커 카드 |
| 최대 크기 | ~480 × 600 |
| 사용 시점 | 짧은 정보 조회 / 작은 컨트롤 / 컬렉션 조회 |
| 닫힘 트리거 | 외부 클릭 / ESC / 트레이 아이콘 재클릭 |
| 사용자 시각 | 트레이 아이콘 아래에 작은 카드가 떠올라 잠깐 보고 닫음 |
| 예시 | 시계, 미니맵 컨트롤, 웨이포인트 목록, 메모 목록, 알림 |

### 2.3 모달 (Modal)

| 항목 | 값 |
|---|---|
| 컨테이너 | 전체 화면 오버레이 + 백드롭 |
| 닫힘 트리거 | X 버튼 / ESC / (옵션: 외부 영역 클릭) |
| 사용 시점 | 별도 작업 컨텍스트, 긴 작업, 진지한 진입 |
| 사용자 시각 | 워크스페이스 위에 큰 다이얼로그가 떠 백드롭 차단. 명시적으로 닫아야 함 |
| 예시 | 설정(SettingsUI), 계정(account 카테고리), 결제, 워크스페이스 생성 다이얼로그 |

### 2.4 핀보드 인스턴스 (Pin Instance) — 기본 wrapper

| 항목 | 값 |
|---|---|
| 컨테이너 | 핀보드 레이어 + 인스턴스 wrapper |
| 데이터 소유 | **자기 데이터** (편집/저장 가능 컨텐츠) |
| 위치 | `transforms.pinboard` 자유 좌표. 드래그 자유 |
| 크기 | 자유 리사이즈 |
| 인터랙션 | 컴포넌트 자유 (액션 버튼 / 수치 / 편집) |
| z-index | default (캔버스 객체와 같은 레벨) |
| 초기 위치 | 우상단 부근 (현 인프라 default) |
| 닫힘 | X 버튼 / 우클릭 토글 |
| 예시 | 메모, 투두, 샌드박스/문서 본체, 미니맵 인스턴스 옵션 |

### 2.5 핀보드 위젯 (Pin Widget) — 같은 인프라 + 컴포넌트의 ui 분기

**핀보드 인프라 동일** (`openInPinboard`, `AppObjectData`, `transforms.pinboard`, LiveDoc 동기화). **wrapper / 메타 필드 / enum / 별도 인프라 다 X**.

위젯 = **컴포넌트 자체가 `mode === 'pin'` 일 때 ui 다르게 그림**. 표준 사례 = MinimapApp:

```ts
// 컴포넌트 안 3가지 분기:
get transparentBackground() {
  return this.mode === 'pin';   // 투명 배경 (캔버스에 떠있는 느낌)
}
get titleBarMode() {
  return this.mode === 'pin' ? 'auto-hide' : 'auto';   // 타이틀바 자동 숨김
}
renderContent() {
  return this.mode === 'pin' ? <PinView /> : <DefaultView />;   // 위젯 전용 컨텐츠
}
```

**분류 = 시스템 고정 (컴포넌트 코드)**. 사용자가 메뉴/우클릭에서 위젯/인스턴스 모드 변경 X.

**확정 위젯 = 미니맵**. 다른 도구(시계/알림 등)는 위젯 분류 미확정 — 도구 신설 / 결정 시점에 컴포넌트 mode 분기 추가 여부 결정.

---

## 3. 결정 가이드 — 어느 패턴?

새 앱/도구 등록 시 다음 순서로 판단:

```
1. 토글 1개로 끝나는가?
   YES → 즉시 액션
   NO  → 2

2. 별도 화면 진입이 필요한 긴 작업인가?
   YES → 모달
   NO  → 3

3. 항상 떠 있어야 의미 있는가? (모니터링 / 작업 옆에 둠)
   NO  → 팝업 (잠깐 보고 닫음)
   YES → 4

4. 핀보드에 띄우되 — 일반 앱처럼 헤더+컨텐츠 형태?
   YES → 핀보드 인스턴스 (메모/투두/문서)
   NO  (캔버스/시스템 거울 + 미니멀 ui) → 핀보드 위젯 (미니맵 등)
```

### 핀보드 인스턴스 vs 위젯 — 같은 인프라

같은 `openInPinboard(appId, appType)`. 차이는 **컴포넌트 자체가 `mode === 'pin'` 분기로 ui 다르게 그리는지**:
- 분기 안 함 = 인스턴스 (default frame: 헤더 + 컨텐츠)
- 분기 함 = 위젯 (transparentBackground / titleBarMode='auto-hide' / 위젯 전용 renderContent)

### 분류 = 시스템 고정 (컴포넌트 코드)

도구 컴포넌트가 자기 정체를 코드로 박아둠. 사용자가 메뉴/우클릭에서 모드 변경 X. 별도 메타 필드 / enum / wrapper / 호출 옵션 다 **불필요** — `openInPinboard` 호출만으로 시스템이 알아서. 컴포넌트의 mode 분기가 곧 분류.

---

## 4. 좌/우클릭 분리 원칙

| 클릭 | 의미 |
|---|---|
| 좌클릭 | **주된 동작 1개** (그 앱의 정체성 = 가장 흔한 사용) |
| 우클릭 | 서브 액션 / 카테고리 단축 (선택적). 좌클릭과 다른 출력 패턴 가능 (예: 좌클릭=팝업, 우클릭 "고정"=핀보드) |

---

## 5. 컴포넌트 wrapper (인프라 매핑)

| 패턴 | wrapper / 분기 | 호출 / 등록 |
|---|---|---|
| 즉시 액션 | 없음 | `TrayItem.onClick` |
| 팝업 | `TrayPopupWrapper` (메뉴바 앵커 + max 크기 + ESC/외부 클릭 닫힘) | `TrayItem.renderPopup` 또는 AppKit `app.tray.setPopup` |
| 모달 | `Dialog` 또는 도메인별 (e.g. `SettingsUI`) | (모달은 별도 — 직접 mount) |
| 핀보드 인스턴스 | (default — `AppObject` 기본 frame: 헤더 + 컨텐츠) | `_objectService.openInPinboard(appId, appType)` |
| 핀보드 위젯 | **컴포넌트 자체 mode 분기** (`transparentBackground` / `titleBarMode` / `renderContent` getter override). wrapper 컴포넌트 X | `_objectService.openInPinboard(appId, appType)` (인스턴스와 호출 동일) |

> **현 인프라 상태**:
> - 팝업 / 핀보드 인스턴스 / 핀보드 위젯 = 인프라 다 존재
> - **위젯 = 별도 인프라 신설 X**. 컴포넌트가 `mode === 'pin'` 분기 추가하면 자동 위젯
> - 표준 사례 = MinimapApp (`transparentBackground=true` + `titleBarMode='auto-hide'` + `renderContent` 분기)
> - 모달 = 도메인별 (공통 wrapper 없음)

---

## 6. 현 트레이 앱 분류 (적용 사례)

**핀보드 모드 = 컴포넌트 코드로 고정** (mode 분기 유무가 곧 분류).

| 앱 | 좌클릭 | 우클릭 | 핀보드 모드 |
|---|---|---|---|
| MinimapApp | 팝업 (미니맵 + 줌/그리드 컨트롤) | "항상 표시" | **위젯 (확정)** — `transparentBackground=true` + `titleBarMode='auto-hide'` + `renderContent` 분기 (표준 사례) |
| ClockApp | 팝업 (시간/날짜 카드) | 위젯 추가 / 시간 설정 | **미정** — 앱 본체로 들어갈 여지 있음 |
| WaypointApp | 팝업 (웨이포인트 목록 + 저장 UI) | (없음) | (현재 핀보드 사용 X) |
| MemoApp | 팝업 (메모 목록) | 새 메모 / 모두 펼치기 / 모두 접기 | **인스턴스 (확정)** — 자기 데이터 본체 |
| SettingsApp | 모달 (SettingsUI 홈) | 카테고리 단축 | (모달 전용 — 핀보드 무관) |
| ProfileApp | 모달 (SettingsUI account) | (없음) | (모달 전용) |
| MenuBarVisibilityApp | 즉시 액션 (메뉴바 pin 토글) | (없음) | (액션 전용) |
| HiddenTrayApp | 즉시 액션 (》/《 펼침 토글) | (없음 — 우클릭 미지원) | (액션 전용) |
| Memo/Todo/Sandbox/Doc 본체 | (트레이 외 — 캔버스 컨텐츠) | — | **인스턴스 (확정)** — 자기 데이터 |

---

## 7. 미해결 / TODO

- ~~**핀보드 위젯 wrapper / 메타 / 분기 인프라 신설**~~ — **불필요로 결론** (2026-04-25). MinimapApp 이 이미 `mode === 'pin'` 분기 (`transparentBackground` / `titleBarMode='auto-hide'` / `renderContent` 별도 뷰) 로 위젯 패턴 구현 완료 = 표준. wrapper 컴포넌트 / `pinMode` 메타 / `PIN_AS_WIDGET` 정적 속성 / `ObjectFactory` 분기 다 도입 X. 다른 도구가 위젯이 되려면 = 컴포넌트 안 mode 분기 직접 추가
- **`043-pinboard-widget` task 처리** — wrapper 방향 잘못된 채 작성됨. 폐기 또는 "MinimapApp 패턴 가이드" 로 재정의 (사용자 결정 대기)
- **시계 / 알림 등 위젯 분류** — 본 문서에서 미확정. 시계는 앱 본체로 들어갈 여지 있음. 도구 신설/논의 시점에 결정
- **미니맵 본체 통합** — `MinimapPopup` / `MinimapPinView` 가 공통 `MinimapCanvas` 사용하도록 정리 (별도 라운드 — 예: `028-minimap-refactor`)
- **모달 공통 wrapper** — 현재 모달은 도메인별 자체 구현 (SettingsUI 등). 공통 `Dialog` 컴포넌트 신설로 통일 가능 (선택)

---

## 8. 관련 문서

- `product/uxui/05-menubar/00-MENUBAR.md §1.3 트레이` — 트레이 영역 정의 + 히든 기능
- `product/uxui/05-menubar/00-MENUBAR.md §2 독` — 캔버스 앱 (핀보드 인스턴스의 컨테이너 정의)
- `fricle/app/modules/workspace/docs/tasks/019-tray/polish/` — 트레이 boundary 모델 + 우클릭 규약 (결정 5)
- `fricle/app/modules/workspace/docs/tasks/017-menubar/polish/` — 메뉴바 좌측 정체성 + 트레이 우측 고정 4종
- `fricle/app/modules/workspace/client/src/objects/apps/minimap/MinimapApp.tsx` — 위젯 패턴 표준 사례 (`mode === 'pin'` 분기)
- (TODO) `fricle/app/modules/workspace/docs/tasks/028-minimap-refactor/` — 미니맵 본체 공통화 (`MinimapPopup` / `MinimapPinView` / `MinimapCanvas`)
