<b>OLEDi Commander</b>

Software Requirements Specification

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

항목내용
문서 버전v1.0
작성일2026-03-21
최종 검토일2026-03-21
상태초안 (Draft)
대상 플랫폼Windows 10 / 11 (x64)
구현 언어C# / .NET 8 / WPF

<br/>

<b>목차</b>

<br/>

<b>1. 개요 (Overview)</b>

<b>1.1 프로젝트 목적</b>

OLEDi Commander는 macOS 생산성 도구 Alfred에서 영감을 받아, Windows 환경에서 동등하거나 그 이상의 생산성을 제공하기 위해 설계된 키보드 우선(Keyboard-first) 런처 겸 워크스페이스 매니저입니다.

전통적인 마우스 중심 UI 조작을 Alt+Space 단축키 하나로 대체하여, 개발자·파워유저가 컨텍스트 전환 비용 없이 빠르게 작업을 수행할 수 있도록 합니다.

<b>1.2 범위 (Scope)</b>

본 문서는 OLEDi Commander 1.0 릴리스를 대상으로 하며, 아래 두 핵심 모듈을 포함합니다.

아래 항목은 v1.0 범위에서 제외됩니다.

<b>1.3 용어 정의 (Glossary)</b>

용어정의
HWNDWindows API에서 창(Window)을 식별하는 핸들 값
Rect창의 좌상단·우하단 좌표로 이루어진 사각형 구조체
Profile특정 시점의 창 배치 및 크기 정보를 저장한 JSON 객체
Alias긴 경로·명령을 짧게 치환하는 사용자 정의 키워드
Fuzzy Search오타·부분 입력도 유사 항목을 찾아주는 비정확 검색
Global Hook어떤 앱이 포커스를 갖고 있어도 키 입력을 감지하는 OS 훅
PluginCommandResolver에 새로운 ActionHandler를 추가하는 확장 단위
SkillPlugin의 다른 표현. 사용자 정의 실행 규칙 묶음
settings.json사용자 설정 및 Alias를 저장하는 로컬 JSON 파일

<b>1.4 참조 문서</b>

<br/>

<b>2. 시스템 아키텍처</b>

OLEDi Commander는 단일 프로세스(Single-process) 구조이며, 아래 5개 핵심 모듈로 구성됩니다. 모든 모듈은 의존성 주입(DI) 방식으로 연결되어 테스트 및 확장이 용이합니다.

모듈역할핵심 기술
Input Listener글로벌 키 훅 – 어떤 앱에서도 Alt+Space 감지WH_KEYBOARD_LL, RegisterHotKey
Context Manager열린 창의 HWND, Rect, 프로세스 경로 수집 및 복원EnumWindows, GetWindowPlacement, SetWindowPos
Command Resolver입력 텍스트 파싱 → ActionHandler 라우팅Prefix 테이블, ActionHandler 인터페이스
Fuzzy Engine파일명·키워드 부분 입력으로 빠른 유사 항목 탐색Fuse.js 알고리즘 포팅 또는 FuzzySharp
Plugin Host외부 .dll 또는 JSON 기반 스킬을 로드·실행Reflection, IActionHandler 인터페이스

<b>2.1 모듈 간 데이터 흐름</b>

[사용자 키 입력] → Input Listener → Command Resolver → ActionHandler (Shifter / Alfred / Plugin)

[창 배치 저장] → Context Manager → Profile JSON → settings.json

[창 배치 복원] → settings.json → Context Manager → User32 API

<b>2.2 Prefix 라우팅 테이블</b>

Command Resolver는 입력 텍스트의 첫 번째 토큰(prefix)을 기준으로 ActionHandler를 선택합니다. 빌트인 prefix는 다음과 같습니다.

Prefix타입예시동작
!워크스페이스!dev저장된 "dev" 프로필 즉시 복원
@URL / 웹@blogsettings.json의 해당 URL 브라우저로 오픈
#동적 API#jira설정된 API 어댑터 호출 후 결과 표시
>터미널 명령>git statusWindows Terminal / PowerShell에서 실행
~파일 경로~projects등록된 폴더 경로를 탐색기로 오픈
(없음)Fuzzy 검색vsc인덱스에서 유사 파일·앱·Alias 검색
확장 가능성
위 prefix 목록은 settings.json의 "prefixMap" 배열을 통해 사용자가 직접 추가·변경할 수 있습니다.
플러그인 개발자는 IActionHandler 인터페이스를 구현하는 .dll을 제공하여 새로운 prefix 동작을 등록합니다.
자세한 내용은 섹션 7 개발자 확장 가이드를 참조하십시오.

<br/>

<b>3. 기능 요구사항</b>

<b>3.1 워크스페이스 스냅샷 & 시프트 (The Shifter)</b>

"어떤 위치에 어떤 크기로" 떠 있는지까지 관리하는 워크스페이스 레이아웃 엔진입니다. 단순 앱 실행을 넘어 창의 상태(State)를 완전히 복원합니다.

<b>3.1.1 Snapshot Capture</b>

<b>3.1.2 Instant Restore</b>

<b>3.1.3 Profile 관리</b>

<b>3.1.4 Multi-Monitor 지원</b>

<b>3.2 시맨틱 커맨드 런처 (The Alfred)</b>

키보드만으로 마우스 클릭 수십 번의 가치를 만들어냅니다. Alt+Space → 명령어 입력의 단일 패턴으로 모든 작업을 처리합니다.

<b>3.2.1 Smart Aliases</b>

긴 경로나 복잡한 명령을 짧은 별칭으로 등록합니다. settings.json의 "aliases" 배열로 관리됩니다.

Alias 타입예시동작 설명
url@blog → https://swarchitect.net/admin브라우저로 URL 오픈
folder~proj → C:\\Dev\\Projects탐색기로 폴더 오픈
app@term → C:\\Windows\\wt.exe지정 실행파일 실행
batch>build → cmd /c build.bat커맨드 실행 (출력 창 선택)
api#jira → JiraAdapter (토큰 설정 필요)동적 데이터 조회 후 결과 표시
clipboard$upper → UPPER_CASE 변환현재 클립보드 텍스트 변환

<b>3.2.2 Fuzzy Engine</b>

<b>3.2.3 Clipboard Transformer</b>

복사한 텍스트를 규칙에 따라 가공합니다. $ prefix로 호출하며, 변환 결과를 클립보드에 덮어쓴 후 활성 창에 붙여넣기(Ctrl+V) 시뮬레이션을 수행합니다.

빌트인 변환명령예시
JSON 포맷팅$json{"a":1} → 들여쓰기 적용 JSON
유닉스 타임스탬프 → 날짜$ts1700000000 → 2023-11-14 22:13:20
날짜 → 유닉스 타임스탬프$epoch2023-11-14 → 1700000000
대문자 변환$upperhello → HELLO
소문자 변환$lowerHELLO → hello
URL 인코딩$urle한글 → %ED%95%9C%EA%B8%80
URL 디코딩$urld%ED%95%9C%EA%B8%80 → 한글
Base64 인코딩$b64etext → dGV4dA==
Base64 디코딩$b64ddGV4dA== → text
마크다운 → 텍스트$md**bold** → bold

사용자 정의 변환 규칙은 settings.json의 "clipboardTransformers" 배열에 추가하며, 정규식 기반 변환과 외부 스크립트 호출을 지원합니다. 자세한 내용은 섹션 7.4를 참조하십시오.

<b>3.3 동적 API Alias (#)</b>

# prefix를 사용하는 Alias는 외부 API를 호출하여 동적 결과를 표시합니다. 각 API 연결은 "apiAdapters" 설정으로 정의합니다.

항목요구사항
인증Personal Access Token(PAT) 또는 OAuth 2.0. 토큰은 Windows Credential Manager에 저장
네트워크 오류3초 내 응답 없으면 타임아웃, 오프라인 캐시(최대 1시간) 표시
결과 표시최대 10개 항목을 런처 결과 리스트에 표시, Enter로 기본 동작(URL 오픈) 실행
빌트인 어댑터Jira Cloud, GitHub Issues (v1.0). 추가 어댑터는 플러그인으로 제공

<br/>

<b>4. UI/UX 디자인 요구사항</b>

<b>4.1 런처 윈도우</b>

요소명세
형태화면 중앙 상단 1/3 지점에 위치하는 반투명 바(Bar) 형태 오버레이
기본 크기너비: 680px, 높이: 54px (입력 상태). 결과 표시 시 높이 자동 확장
투명도Opacity 0.96 (기본). settings.json에서 0.7~1.0 조정 가능
테마시스템 다크/라이트 모드 자동 감지(WMI 또는 레지스트리 감시). 수동 고정 설정 가능
폰트Segoe UI (영문), Malgun Gothic (한글), 16px
애니메이션호출: 상단 20px에서 Fade-in + SlideDown (120ms). 닫힘: Fade-out (80ms)
항상 최상위Topmost = true. 다른 창에 가려지지 않음
포커스 처리런처 외부 클릭 시 자동 닫힘 (LostFocus 이벤트)

<b>4.2 결과 리스트</b>

<b>4.3 접근성 (Accessibility)</b>

<br/>

<b>5. 비기능 요구사항 (NFR)</b>

<b>5.1 성능</b>

항목목표 수치측정 방법
Fuzzy 검색 응답< 100ms (p95)로컬 인덱스 10,000건 기준 자동화 벤치마크
Instant Restore (5창 기준)< 1.5초스톱워치 측정, 5회 평균
앱 시작 시간< 800ms (백그라운드 Ready 상태)프로세스 시작 → 트레이 아이콘 표시까지
메모리 사용량유휴 시 < 80MB RSSProcess Explorer 모니터링
CPU 점유율유휴 시 < 0.5%10분 유휴 후 평균
인덱싱 시간10,000파일 < 3초초기 기동 시 측정

<b>5.2 신뢰성 & 안정성</b>

<b>5.3 보안</b>

보안 주의사항 – Windows Defender / EDR 탐지
WH_KEYBOARD_LL 훅은 일부 보안 소프트웨어에서 키로거로 오탐될 수 있습니다.
대응 방안: 앱 배포 시 코드 서명 인증서 적용, Microsoft Store 등록 검토.
기업 환경 배포 시에는 GPO 화이트리스트 등록 가이드를 별도 제공합니다.

<b>5.4 유지보수성</b>

<b>5.5 호환성</b>

<br/>

<b>6. 예외 처리 및 엣지 케이스</b>

시나리오원인처리 방침
Restore 시 앱 미실행저장된 EXE가 닫혀 있음자동 EXE 실행 → 3초 대기 → 실패 시 건너뜀, 결과 알림
모니터 구성 변경모니터 추가/제거/해상도 변경settings.json의 "monitorMismatch" 정책에 따라 fit/skip/warn
단축키 충돌타 앱이 Alt+Space 선점등록 실패 감지 → 트레이에 경고 → 대체 단축키 제안
관리자 권한 창 제어타 프로세스가 elevatedSetWindowPos 예외 캐치 → 해당 창 건너뜀, 로그 기록
settings.json 손상JSON 파싱 오류원본 .bak 저장 → 기본값 로드 → 복구 안내 메시지
Alias 중복 등록동일 키워드 중복나중에 추가된 항목이 우선. 경고 로그 기록
플러그인 로드 실패.dll 서명 불일치 또는 예외해당 플러그인 건너뜀, 오류 로그. 앱은 계속 실행
API 타임아웃네트워크 불안정3초 타임아웃 → 오프라인 캐시 표시 (1시간 유효) → 캐시 없으면 오류 메시지
앱 인덱스 폴더 접근 불가권한 없는 폴더해당 폴더 스킵, 인덱싱 완료 후 경고 로그
Fuzzy 검색 결과 없음입력에 일치 항목 없음"일치하는 항목이 없습니다" 표시, 입력 지속 허용

<br/>

<b>7. 데이터 스키마 (settings.json)</b>

모든 사용자 설정과 Profile, Alias는 단일 JSON 파일로 관리됩니다. 파일 위치: %APPDATA%\OLEDiCommander\settings.json

{

"version": "1.0",

"hotkey": "Alt+Space",

"launcher": {

"opacity": 0.96,

"maxResults": 7,

"theme": "system",

"position": "center-top"

},

"indexPaths": [

"%USERPROFILE%\\Desktop",

"%APPDATA%\\Microsoft\\Windows\\Start Menu"

],

"monitorMismatch": "warn",

"profiles": [

{

"name": "dev",

"windows": [

{

"exe": "C:\\Program Files\\Microsoft VS Code\\Code.exe",

"title": "Visual Studio Code",

"rect": { "x": 0, "y": 0, "width": 1280, "height": 1080 },

"showCmd": "Normal",

"monitor": 0

}

]

}

],

"aliases": [

{ "key": "@blog", "type": "url", "target": "https://swarchitect.net/admin" },

{ "key": "#jira", "type": "api", "adapter": "jira", "query": "assignee=currentUser() ORDER BY updated DESC" },

{ "key": "~proj", "type": "folder", "target": "C:\\Dev\\Projects" },

{ "key": ">build", "type": "batch", "target": "cmd /c C:\\Dev\\build.bat", "showWindow": false }

],

"clipboardTransformers": [

{ "key": "$myRule", "type": "regex", "pattern": "(\\d{4})-(\\d{2})-(\\d{2})", "replace": "$3/$2/$1" }

],

"apiAdapters": [

{ "id": "jira", "baseUrl": "https://yourorg.atlassian.net", "credentialKey": "jira_pat" }

],

"plugins": [

{ "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }

]

}

<br/>

<b>8. 개발자 확장 가이드 (Plugin & Skill Development)</b>

이 섹션은 OLEDi Commander에 새로운 기능, 명령어, API 연결, 변환 규칙을 추가하려는 개발자를 위한 문서입니다. 확장 방법은 세 가지 경로로 제공됩니다.

확장 방법난이도추천 대상
settings.json 수정쉬움URL Alias, 폴더 단축키, 배치 명령 추가
JSON 스킬 파일 (.skill.json)보통API 어댑터, 커스텀 변환 규칙
.dll 플러그인 (C# IActionHandler)어려움완전히 새로운 명령 타입, UI 커스터마이징

<b>8.1 settings.json으로 Alias 추가하기</b>

가장 간단한 확장 방법입니다. settings.json 파일을 텍스트 에디터로 열어 "aliases" 배열에 항목을 추가합니다.

// URL 열기 Alias 추가

{ "key": "@notion", "type": "url", "target": "https://notion.so/your-workspace" }

// 폴더 열기 Alias 추가

{ "key": "~dl", "type": "folder", "target": "%USERPROFILE%\\Downloads" }

// 배치 파일 실행 Alias 추가 (출력 창 표시)

{ "key": ">deploy", "type": "batch", "target": "cmd /c C:\\deploy.bat", "showWindow": true }

// 배치 파일 실행 Alias 추가 (백그라운드 실행)

{ "key": ">silent", "type": "batch", "target": "powershell -File C:\\task.ps1", "showWindow": false }

팁: 환경변수 사용
"target" 값에 %USERPROFILE%, %APPDATA%, %TEMP% 등 Windows 환경변수를 사용할 수 있습니다.
앱 실행 시 자동으로 확장됩니다.

<b>8.2 Clipboard Transformer 규칙 추가하기</b>

settings.json의 "clipboardTransformers" 배열에 변환 규칙을 추가합니다. 정규식(regex) 또는 외부 스크립트(script) 타입을 지원합니다.

// 정규식 변환: 날짜 형식 YYYY-MM-DD → DD/MM/YYYY

{

"key": "$date",

"type": "regex",

"pattern": "(\\d{4})-(\\d{2})-(\\d{2})",

"replace": "$3/$2/$1",

"description": "ISO 날짜를 로컬 날짜 형식으로 변환"

}

// PowerShell 스크립트 호출 변환

{

"key": "$ps",

"type": "script",

"command": "powershell -NoProfile -Command \"$input | ConvertTo-Json\"",

"timeout": 5000,

"description": "클립보드 텍스트를 PowerShell로 처리"

}

스크립트 타입의 경우, 앱은 클립보드 텍스트를 stdin으로 전달하고 stdout 결과를 클립보드에 저장합니다. timeout(ms) 초과 시 원본 텍스트를 유지합니다.

<b>8.3 JSON 스킬 파일로 API Adapter 추가하기</b>

새로운 API 서비스(예: Notion, Linear, Slack)를 연결하려면 .skill.json 파일을 작성합니다. 파일은 %APPDATA%\OLEDiCommander\skills\ 폴더에 저장합니다.

// %APPDATA%\OLEDiCommander\skills\notion.skill.json

{

"id": "notion",

"name": "Notion 페이지 검색",

"version": "1.0",

"prefix": "#notion",

"credential": {

"type": "bearer_token",

"credentialKey": "notion_api_token"

},

"request": {

"method": "POST",

"url": "https://api.notion.com/v1/search",

"headers": { "Notion-Version": "2022-06-28" },

"body": { "query": "{{INPUT}}", "page_size": 10 }

},

"response": {

"resultsPath": "results",

"titleField": "properties.title.title[0].plain_text",

"subtitleField": "url",

"actionUrl": "url"

},

"cache": { "ttl": 300 }

}

{{INPUT}}은 사용자가 # 이후에 입력한 텍스트로 치환됩니다. 토큰은 앱 내 설정 화면에서 입력하며 Windows Credential Manager에 암호화 저장됩니다.

필드필수설명
id스킬 고유 식별자 (영문 소문자, 하이픈 허용)
prefix런처에서 이 스킬을 호출하는 명령어 (예: #notion)
credential.typebearer_token / basic_auth / oauth2 중 선택
request.urlAPI 엔드포인트. {{INPUT}}, {{TOKEN}} 템플릿 변수 사용 가능
response.resultsPathJSON 응답에서 결과 배열 경로 (dot notation)
response.actionUrlEnter 시 열리는 URL 필드 경로
cache.ttl아니오결과 캐시 유효 시간(초). 기본값 0 (캐시 없음)

<b>8.4 C# .dll 플러그인으로 새 ActionHandler 개발하기</b>

완전히 새로운 명령 타입, 복잡한 UI, 또는 OS 레벨 기능이 필요한 경우 C# 플러그인을 개발합니다.

<b>8.4.1 인터페이스 정의</b>

// OLEDiCommander.SDK NuGet 패키지 설치 후 사용

using OLEDiCommander.SDK;

/// <summary>

/// 모든 플러그인은 이 인터페이스를 구현해야 합니다.

/// </summary>

public interface IActionHandler

{

// 이 핸들러가 처리할 prefix (예: "@", "#", "!") 또는 null (Fuzzy 결과에만 등록)

string? Prefix { get; }

// 런처 결과 리스트에 표시할 항목을 반환합니다.

// query: prefix 이후의 입력 텍스트

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

// 사용자가 항목을 선택(Enter)했을 때 실행됩니다.

Task ExecuteAsync(LauncherItem item, CancellationToken ct);

// 플러그인 메타데이터

PluginMetadata Metadata { get; }

}

public record LauncherItem(

string Title,

string Subtitle,

string? IconPath, // null이면 기본 아이콘 사용

object? Data // ExecuteAsync에 전달되는 임의 데이터

);

public record PluginMetadata(

string Id,

string Name,

string Version,

string Author

);

<b>8.4.2 예제: 계산기 플러그인</b>

using OLEDiCommander.SDK;

using System.Data;

[Export(typeof(IActionHandler))]

public class CalculatorHandler : IActionHandler

{

public string? Prefix => "="; // "=2+3" 입력 시 이 핸들러 호출

public PluginMetadata Metadata => new("calculator", "계산기", "1.0", "YourName");

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

{

try

{

var result = new DataTable().Compute(query, null);

return [new LauncherItem($"= {result}", "Enter로 복사", null, result.ToString())];

}

catch

{

return [new LauncherItem("수식 오류", "올바른 수식을 입력하세요", null, null)];

}

}

public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)

{

if (item.Data is string val)

Clipboard.SetText(val); // 결과를 클립보드에 복사

}

}

<b>8.4.3 플러그인 배포 및 등록</b>

{ "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }

개발 팁: 핫 리로드
개발 중에는 시스템 트레이 → "개발자 모드" 활성화 시 플러그인 파일 변경 감지 후 자동 재로드됩니다.
OLEDiCommander.SDK.dll은 NuGet 패키지(OLEDiCommander.SDK)로 배포됩니다.
단위 테스트 시 MockLauncherContext를 주입하여 UI 없이 IActionHandler를 테스트할 수 있습니다.

<b>8.5 확장 체크리스트</b>

새 기능을 추가하기 전에 아래 항목을 확인하십시오.

체크 항목확인 기준
Prefix 충돌 확인기존 Prefix 테이블(섹션 2.2)과 중복 없는지 확인
에러 처리네트워크 오류, 타임아웃, null 결과 등 모든 예외 처리 구현
CancellationToken 사용사용자가 ESC 입력 시 진행 중인 비동기 작업 즉시 취소
캐싱 고려API 호출 결과는 TTL 캐시 적용으로 불필요한 네트워크 요청 방지
로깅 추가ILogger를 통해 DEBUG/ERROR 레벨 로그 기록
단위 테스트GetItemsAsync, ExecuteAsync 각각 최소 1개 이상 테스트 케이스 작성
아이콘 제공32x32 PNG 아이콘을 LauncherItem.IconPath에 포함
설명 작성PluginMetadata.Name, settings.json의 description 필드 작성

<br/>

<b>9. 설치 및 배포</b>

항목내용
배포 형태MSIX 패키지 (Microsoft Store) 또는 Squirrel.Windows 인스톨러 (.exe)
Self-contained.NET 8 Self-contained 배포 – 별도 런타임 설치 불필요
설치 경로%LOCALAPPDATA%\Programs\OLEDiCommander\
설정 경로%APPDATA%\OLEDiCommander\
자동 시작HKCU Run 레지스트리 키 등록 (설치 시 옵션 선택)
자동 업데이트앱 실행 시 GitHub Releases API 버전 확인, 백그라운드 다운로드
제거일반 "앱 및 기능"으로 제거 가능. 설정 파일 유지 여부 선택

<b>10. 미결 사항 및 향후 계획 (v2.0)</b>

항목우선순위비고
플러그인 마켓플레이스 UI높음서드파티 스킬 검색/설치/업데이트 통합 UI
OAuth 2.0 인증 흐름높음GitHub, Google 등 OAuth 기반 API 어댑터 지원
AI 자연어 명령중간예: "1주일 전 내 Jira 티켓 열어줘" → #jira 쿼리 자동 생성
클라우드 설정 동기화중간OneDrive / iCloud Drive를 통한 settings.json 동기화
플러그인 서명 강제화높음v2.0부터 서명 없는 .dll 실행 차단
스크립트 언어 지원낮음Python / Node.js 스크립트를 스킬로 직접 등록
음성 명령 입력낮음Windows Speech API 연동

<b>변경 이력</b>

버전날짜작성자변경 내용
v1.02026-03-21초안 작성 (SRS 전체 구조 + 개발자 확장 가이드 포함)