# AX_Commander_개발문서

<b>AX Commander</b>

개발 문서

Windows 전용 시맨틱 런처 & 워크스페이스 매니저

# 사내 전용 프로그램 개발 원칙

AX Commander는 사내 전용 프로그램입니다. 아래 원칙을 반드시 준수하여 개발하세요.

## 외부 연결 금지

금지 항목 | 설명
--- | ---
외부 HTTP/HTTPS 호출 | HttpClient, WebClient, HttpWebRequest 등으로 외부 서버에 요청 금지
외부 SDK 연동 | 서드파티 클라우드 SDK, AI API, SaaS 라이브러리 사용 금지
원격 플러그인 다운로드 | 런타임에 외부에서 DLL/코드 다운로드 금지
텔레메트리 / 오류 수집 | 사용 데이터를 외부 서버로 전송하는 일체의 코드 금지
NuGet 패키지 | 외부 네트워크 통신이 내장된 패키지 신규 도입 금지

허용: 로컬 파일 시스템 접근, Windows API (P/Invoke), 사내 인트라넷 URL, 로컬 프로세스 실행

# 아키텍처 개요

## 핵심 컴포넌트

컴포넌트 | 역할
--- | ---
App.xaml.cs | 앱 진입점, 서비스 초기화, 트레이 아이콘 관리
LauncherWindow | WPF 메인 UI (AllowsTransparency, WindowStyle=None)
CommandResolver | 프리픽스 기반 핸들러 라우팅 테이블
FuzzyEngine | 퍼지 검색 + 한국어 초성(ㅅㄷ) 매칭
IndexService | 파일 시스템 인덱서 + FileSystemWatcher
SettingsService | settings.json 로드/저장 (자동 백업)
ClipboardHistoryService | WM_CLIPBOARDUPDATE 훅 기반 히스토리
PluginHost | DLL/JSON 스킬 플러그인 로더
NotificationService | 트레이 풍선 알림 (타이머/알람)

# 프리픽스 핸들러 치트시트

프리픽스 | 핸들러 | 기능
--- | --- | ---
(없음) | FuzzyEngine | 앱·파일 퍼지 검색 + 한국어 초성
= | CalculatorHandler | 수식 계산, 단위/통화 변환
/ | SystemCommandHandler | lock, sleep, restart, shutdown, timer, alarm
; | SnippetHandler | 텍스트 스니펫 키워드 검색 & 붙여넣기
# | ClipboardHistoryHandler | 클립보드 히스토리 검색 & 병합
@ | UrlAliasHandler | URL 단축키
~ | FolderAliasHandler | 폴더 단축키
> | BatchHandler | 명령 실행 / 배치 단축키
$ | ClipboardHandler | 클립보드 텍스트 12종 변환
! | WorkspaceHandler | 워크스페이스 저장·복원
emoji | EmojiHandler | 이모지 피커 (300+)
color | ColorHandler | HEX/RGB/HSL/HSV 색상 변환
recent | RecentFilesHandler | Windows 최근 파일
note | NoteHandler | 빠른 메모 저장·조회
uninstall | UninstallHandler | 앱 제거 (레지스트리)
port | PortHandler | TCP 포트/프로세스 점검
env | EnvHandler | 환경변수 조회
json | JsonHandler | JSON 검증/포맷/미니파이
encode | EncodeHandler | base64/url/hex/md5/sha256 인코딩
snap | SnapHandler | 창 배치 레이아웃
cap | ScreenCaptureHandler | 화면/창/스크롤 캡처
help | HelpHandler | 도움말

# 설정 스키마 (settings.json)

경로: %APPDATA%\AxCommander\settings.json

키 | 타입 | 설명
--- | --- | ---
version | string | 설정 버전
hotkey | string | 글로벌 단축키 (기본: Alt+Space)
launcher.opacity | float | 창 투명도 (0.0~1.0, 기본 0.96)
launcher.maxResults | int | 최대 결과 수 (기본 7)
launcher.theme | string | 테마 (system|dark|light|oled|nord|monokai|catppuccin|sepia|alfred|alfredlight|custom)
launcher.position | string | 런처 위치 (center-top|center|bottom)
launcher.webSearchEngine | string | 기본 검색 엔진 (g|n|d|y|w)
launcher.snippetAutoExpand | bool | 스니펫 자동 확장 활성화
indexPaths | string[] | 인덱싱할 폴더 경로 목록
aliases | object[] | URL/폴더/배치 단축키 목록
snippets | object[] | 텍스트 스니펫 목록
clipboardHistory.enabled | bool | 클립보드 히스토리 활성화
clipboardHistory.maxItems | int | 최대 보관 개수 (기본 50)
plugins | object[] | DLL 플러그인 경로 목록

# 테마 시스템

## 내장 테마 목록

테마 키 | 이름 | 특징
--- | --- | ---
system | 시스템 | Windows 다크/라이트 모드 자동 감지
dark | Dark | 딥 네이비 다크 (기본)
light | Light | 클린 화이트 라이트
oled | OLED | 순수 블랙 (OLED 절전)
nord | Nord | Arctic 컬러 팔레트
monokai | Monokai | Sublime Text 스타일
catppuccin | Catppuccin | Mocha 따뜻한 파스텔
sepia | Sepia | 황갈색 아날로그 감성
alfred | Alfred Dark | Alfred 5 다크 팔레트 (딥 퍼플-차콜)
alfredlight | Alfred Light | Alfred 5 라이트 팔레트 (클린 화이트)
custom | 커스텀 | 14개 색상 완전 커스터마이징

## 테마 ResourceKey 목록 (14개)

키 | 용도
--- | ---
LauncherBackground | 전체 배경
ItemBackground | 항목 기본 배경
ItemSelectedBackground | 선택된 항목 배경
ItemHoverBackground | 호버 배경
PrimaryText | 주 텍스트 색상
SecondaryText | 보조 텍스트 색상
PlaceholderText | 플레이스홀더 텍스트
AccentColor | 강조색 (선택 바, 배지 등)
SeparatorColor | 구분선 색상
HintBackground | ESC 힌트 배경
HintText | ESC 힌트 텍스트
BorderColor | 창 테두리
ScrollbarThumb | 스크롤바 색상
ShadowColor | 드롭 섀도우 색상

## 새 테마 추가 절차

- 1. Themes/MyTheme.xaml 작성 (위 14개 키 모두 정의)
- 2. AxCommander.csproj에 <Resource Include="Themes/MyTheme.xaml"/> 추가
- 3. LauncherWindow.xaml.cs → GetEffectiveThemeName() switch에 케이스 추가
- 4. SettingsViewModel.ThemeCards 목록에 ThemeCardModel 항목 추가

# 보안 고려사항

항목 | 구현
--- | ---
URL 스킴 검증 | http, https, ftp, ms-settings, mailto, file 허용. javascript: 등 차단
PowerShell 인젝션 방지 | > 명령어 입력의 " 이스케이프 처리
ReDoS 방지 | 사용자 정의 Regex에 TimeSpan 타임아웃 적용
자격증명 저장 | Windows Credential Manager (advapi32.dll, DPAPI 암호화)
클립보드 민감 데이터 | Regex 기반 제외 패턴 — 신용카드·IP 등 기본 차단
API 타임아웃 | JSON 스킬 HTTP 요청 3초 제한
시스템 명령 확인 | 재시작·종료·로그아웃 실행 전 MessageBox.Show 2단계 확인

# 단위 테스트

파일 | 테스트 수 | 대상
--- | --- | ---
FuzzyEngineTests.cs | 19 | CalculateScore, FuzzyMatch, 초성 검색
ClipboardTransformTests.cs | 21 | 12개 내장 변환기
SettingsServiceTests.cs | 17 | 기본값, JSON 직렬화 라운드트립

# v1.6 3차 전체 점검 수정

빌드 오류 3건, 컴파일 경고 1건, 런타임 버그 6건, 보안 이슈 2건을 수정하였습니다.

## 컴파일 오류 수정

파일 | 수정 내용 | 오류 코드
--- | --- | ---
UsageRankingService.cs | using System.IO; 누락 추가 | CS0103
SettingsWindow.xaml.cs | Key.Enter or Key.Return 단일 arm으로 통합 | CS8510
ContextManager.cs | EnumDisplayMonitors 람다 타입 혼합 수정 | CS0748

## 런타임 버그 수정

파일 | 버그 | 수정
--- | --- | ---
JsonSkillLoader.cs | field[0 형식 오류 방지 (IndexOf 반환 -1) | closingIdx < 0 가드 추가
ClipboardHistoryService.cs | _ignoreNext 스레드 비안전, 이중 초기화 | volatile + 이중 초기화 가드
IndexService.cs | ScheduleRebuild 타이머 비원자적 교체 | _timerLock으로 원자적 교체
SettingsService.cs | 백업 실패 무음 catch | LogService.Warn으로 기록
LauncherWindow.xaml.cs | Window에 RenderTransform 설정 시 InvalidOperationException | Content(루트 Border)에 적용

## 보안 수정

파일 | 수정 내용
--- | ---
JsonSkillLoader.cs | ActionUrl 실행 전 http/https 스킴 검증 추가
SettingsWindow.xaml.cs | NewIndexPathBox null 역참조 방어 처리

# 빌드 및 배포

## 빌드 명령

# 개발 실행

dotnet run --project src/AxCommander

# Release 단일 파일 빌드 (self-contained)

dotnet publish src/AxCommander -c Release -r win-x64 --self-contained

# 단위 테스트

dotnet test src/AxCommander.Tests

## 데이터 경로

용도 | 경로
--- | ---
설정 파일 | %APPDATA%\AxCommander\settings.json
로그 | %APPDATA%\AxCommander\logs\app-YYYY-MM-DD.log
스킬 파일 | %APPDATA%\AxCommander\skills\*.skill.json
메모 | %APPDATA%\AxCommander\notes.txt
사용 빈도 | %APPDATA%\AxCommander\usage.json
크래시 덤프 | %APPDATA%\AxCommander\crashes\

## 요구 사항

- OS: Windows 10 20H2 이상 (Windows 11 권장)
- .NET 8.0 Runtime (Self-contained 빌드 시 불필요)

# 플러그인 개발

## DLL 플러그인

AxCommander.SDK를 참조하여 IActionHandler 인터페이스를 구현합니다.

using AxCommander.SDK;

public class MyHandler : IActionHandler

{

public string? Prefix => "?"; // 트리거 프리픽스

public PluginMetadata Metadata => new("MyPlugin", "설명", "1.0");

public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)

{

return [ new LauncherItem("제목", "부제목", null, myData, Symbol: "\uE721") ];

}

public Task ExecuteAsync(LauncherItem item, CancellationToken ct)

{

return Task.CompletedTask;

}

}

## JSON 스킬 (코드 없이 HTTP API 연동)

경로: %APPDATA%\AxCommander\skills\*.skill.json

{

"id": "my-api",

"name": "API 연동",

"prefix": "?",

"request": {

"method": "GET",

"url": "https://intranet.example.com/api?q={{INPUT}}"

},

"response": {

"resultsPath": "items",

"titleField": "name",

"subtitleField": "description",

"actionUrl": "url"

},

"cache": 30

}

AX Commander · .NET 8.0 · WPF · MIT License