메인 프로세스 설계
메인 프로세스는 Elftia의 핵심으로, 모든 비즈니스 로직, 외부 API 호출, 데이터베이스 작업 및 보안 제어를 담당합니다. 진입 파일은 packages/desktop/app/main/index.ts입니다.
서비스 모듈 개요
메인 프로세스에는 45개 이상의 서비스 모듈이 포함되어 있으며, packages/desktop/app/main/services/ 하위에 기능 도메인별로 구성되어 있습니다:
graph LR
subgraph "Core Infrastructure"
Core[core/]
Config[config/]
Settings[settings/]
end
subgraph "Auth & Accounts"
Auth[auth/]
Account[account/]
OAuth[oauth/]
end
subgraph "AI Engines"
Engine[engine/]
Completion[completion/]
LLM[llm/]
Prompt[prompt/]
end
subgraph "Agent Orchestration"
Magi[magi/]
Agent[agent/]
Plugin[plugin/]
end
subgraph "Messaging Channels"
Channel[channel/]
Security[security/]
end
subgraph "Media & Content"
Media[media/]
Project[project/]
Search[search/]
end
Core --> Engine
Core --> Channel
Engine --> Magi
LLM --> Completion
Completion --> Engine
Magi --> Agent
Channel --> Security
도메인별 서비스 목록
| 도메인 | 서비스 | 설명 |
|---|---|---|
| Core (core/) | LoggerService | Winston + daily-rotate-file 로깅 |
AppPaths | 애플리케이션 경로 확인 (userData, dbPath, configDir 등) | |
RuntimeService | 런타임 정보 (버전, 채널, 플랫폼) | |
CacheService | 범용 캐시 (TTL 만료 정리) | |
ConfigManager | 설정 파일 관리 | |
SecurityService | AES-256-GCM 암호화 서비스 | |
CryptoService | PBKDF2 키 파생 + 암호화/복호화 | |
PerformanceMonitor | 성능 모니터링 및 알림 | |
ErrorHandler | 전역 오류 처리 | |
PluginManager | 플러그인 생명주기 관리 | |
DatabaseOptimizer | SQLite 최적화 (VACUUM, ANALYZE) | |
CommandService | 명령 실행 서비스 | |
| Auth (auth/) | AuthService | IPC 인증 토큰 유효성 검사 |
AuthSessionService | 로그인 세션 + Deep Link 처리 | |
AuthTokenStore | 인증 토큰 영속성 | |
TokenRefreshService | 자동 토큰 갱신 | |
| Account (account/) | AccountService | 사용자 자격 증명 관리 |
AccountTokensService | OAuth 토큰 관리 | |
LimitsService | 멤버십 한도 확인 | |
| LLM (llm/) | LLMConfigService | 공급자/모델 설정 CRUD |
TransformerService | 요청 형식 변환 체인 | |
| Completion (completion/) | CompletionService | LLM API 호출 진입점 |
ApiKeyPoolService | 다중 키 라운드로빈 + 세션 선호도 | |
| Engine (engine/) | EngineDispatcher | 엔진 등록 및 라우팅 |
ApiEngine | 미디어 API 엔진 | |
ChatEngine | 일반 채팅 엔진 | |
ClaudeSdkEngine | Claude Agent SDK 엔진 | |
TinyElfEngine | 내장 Agent 엔진 | |
CliRunnerEngine | CLI 서브프로세스 엔진 | |
STChatEngine | RP 채팅 파이프라인 엔진 | |
| Magi 오케스트레이션 (magi/) | MagiService | 핵심 메시지 처리 서비스 (assembleMagiMcps를 통해 services/capabilities/tools/mcp-builtin/ 레지스트리로 Clawia의 MCP 집합을 수집하며, buildTinyElfDirectMcpServers는 TinyElf 진입점) |
MagiSessionService | 세션 영속성 관리 | |
MagiWorkspaceService | 작업 공간 디렉토리 관리 | |
MagiSdkOptionsBuilder | 프롬프트 빌드 (V1-V4) + 사용자 MCP 주입 (setUserMcpServers / getMcpServers(allowedUserMcpNames) / getDirectMcpServers) + Channel 프로브; Phase 5.9부터 내장 MCP 어셈블리는 mcp-providers/로 이전 | |
AgentOrchestrator | Agent 디스패치 및 오케스트레이션 | |
AgentDiscovery | 스케줄 가능한 Agent 목록 | |
MessageRouter | 이중 모드 메시지 라우팅 | |
ChannelMagiBridge | Channel에서 Magi로의 브릿지 | |
SessionEventBus | 세션 이벤트 버스 | |
SessionDispatcherImpl | 크로스 세션 디스패치 구현 | |
SubagentRegistry | 하위 Agent 상태 추적 | |
| 내장 MCP 레지스트리 (mcp-providers/) | McpProviderRegistry | 12개 내장 공급자 + 동적 ScriptPlugin 공급자 팩토리. 모든 내장 MCP 핸들러는 인프로세스 실행; SDK가 직접 호출 / TinyElf가 ITool로 등록 / CLI는 중앙 BuiltinMcpHttpServer HTTP 브릿지를 통해 접근. DispatchServer / ChannelServer / VisionAssistServer HTTP 브릿지는 cleanup-legacy-mcp (2026-05-19)에서 제거됨 |
BuiltinMcpHttpServer | 중앙 HTTP MCP 브릿지 (세션 범위); 모든 인프로세스 MCP를 CLI 엔진에 노출 | |
assembleMcpForSession(ctx) | 통합 어셈블리 진입점 (SDK + TinyElf; sdkServers / tinyElfServers / promptFragments / allowedTools / cleanups를 포함하는 McpAssembly 반환) | |
applyAssembly.ts | applyAssemblyToSdkOptions / applyAssemblyToTinyElfConfig — McpAssembly를 엔진 옵션에 병합 | |
contextBuilders.ts | buildAssemblyContextFor{Clawia,Agent} — 호출자 관점에서 AssemblyContext 구성 | |
registerBuiltinMcpProviders.ts | 일회성 부트 어셈블리 포인트 (ScriptPlugin 동일 이름 별칭 처리 포함) | |
builtin/<Name>Provider.ts | 내장 MCP별 Provider 모듈 (정적 12개 + 동적 ScriptPlugin 팩토리) | |
| Channel (channel/) | ChannelPluginLoader | 플러그인 탐색 및 로딩 |
ChannelPluginRegistry | 플러그인 등록 및 인스턴스 관리 | |
ChannelMessageRouter | 메시지 트리거 라우팅 | |
ChannelMarketplaceService | 플러그인 마켓플레이스 | |
| Security (security/) | ExecutionFirewall | 파일 경로 방화벽 |
GuardianAgent | AI 도구 호출 검토 | |
PromptGuardian | 프롬프트 주입 탐지 | |
RateLimiter | 속도 제한 | |
InputSanitizer | 입력 위생 처리 | |
UserPermissionService | 사용자 권한 관리 | |
ChannelPermissionGate | Channel 권한 확인 | |
AuditLogger | 보안 감사 로그 | |
| Media (media/) | ImageGenerationService | 이미지 생성 |
MusicGenerationService | 음악 생성 | |
MediaStorageService | 미디어 파일 저장 | |
MediaResourceService | 콘텐츠 주소 지정 리소스 저장 | |
MediaConfigService | 미디어 공급자 설정 | |
AsrService / TtsService | 음성 인식/합성 | |
| Project (project/) | ProjectService | 프로젝트 CRUD |
FileIndexService | 파일 인덱스 서비스 | |
GitService | Git 작업 | |
| Search (search/) | WebSearchService | 통합 검색 진입점 |
JinaProvider / TavilyProvider / SearxngProvider | 검색 엔진 어댑터 | |
| UI (ui/) | ThemeService | 테마 관리 |
WindowControlsService | 창 컨트롤 | |
TrayService | 시스템 트레이 | |
NotificationService | 데스크톱 알림 | |
| Config (config/) | ConfigStore | electron-store + fs.watch 핫 리로드 |
| Cron (cron/) | CronService | Cron 예약 작업 디스패치 |
| MCP (mcp/) | McpService | MCP 서버 관리 |
| Plugins (plugin/) | ScriptPluginLoader | 스크립트 플러그인 로딩 |
ScriptPluginRegistry | 스크립트 플러그인 레지스트리 | |
ScriptPluginBridgeManager | 플러그인 브릿지 관리 |
IPC 라우터 아키텍처
프론트엔드와 백엔드 간의 모든 통신은 IPC 라우터 레이어를 통해 이루어지며, 현재 68개 이상의 라우터 모듈이 등록되어 있습니다.
secureHandle 패턴
각 IPC 채널은 secureHandle로 감싸져 인증 토큰 유효성 검사를 강제합니다:
{/* packages/desktop/app/main/ipc/safe-handle.ts */}
function secureHandle(
channel: string,
handler: (event: IpcMainInvokeEvent, params: unknown) => Promise<unknown>,
validateToken: (token: string) => boolean,
): void;
흐름:
sequenceDiagram
participant R as Renderer
participant P as Preload
participant S as secureHandle
participant H as Router Handler
R->>P: window.api.someMethod(params)
P->>S: ipcRenderer.invoke(channel, {token, ...params})
S->>S: validateToken(token)
alt token invalid
S-->>P: throw AuthError
else token valid
S->>H: handler(event, params)
H-->>S: result
S-->>P: result
P-->>R: result
end
라우트 등록
모든 라우트는 registerAllRouters()에서 중앙 등록됩니다. 각 Router 클래스는 BaseRouter를 확장하고 register() 메서드에서 채널을 등록합니다:
{/* 단순화된 Router 구조 */}
class SomeRouter extends BaseRouter {
register() {
secureHandle('domain:action', async (_event, params) => {
const validated = SomeSchema.parse(params);
return this.service.doSomething(validated);
}, this.validate);
}
}
라우트 범주 및 수량
| 라우터 디렉토리/파일 | 채널 접두사 | 주요 채널 수 |
|---|---|---|
auth/ | auth:* | 5개 이상 |
account/ | accounts:*, accountTokens:* | 8개 이상 |
session/ | sessions:*, sessionOrganizer:* | 10개 이상 |
chat/ | chatMessages:*, chatAssistants:*, chatControl:*, mediaSession:* | 15개 이상 |
completion/ | completion:* | 5개 이상 |
capabilities/llm/ | llmProviders:*, llmModels:*, apiKeys:*, transformers:* | 15개 이상 |
project/ | projects:*, files:*, git:* | 10개 이상 |
media/ | media:*, imageProviders:*, musicProviders:*, videoProviders:*, asr:*, tts:* | 20개 이상 |
settings/ | settings:*, appPreferences:* | 8개 이상 |
ui/ | theme:*, window:* | 6개 이상 |
MagiRouter | magi:* | 10개 이상 |
ChannelPluginRouter | channels:* | 8개 이상 |
sillytavern/ | characterCards:*, worldInfo:*, regexScripts:*, groupChat:* 등 | 25개 이상 |
| 기타 | mcp:*, webSearch:*, todo:*, tasks:*, notes:*, tags:*, cron:*, elfi:* 등 | 30개 이상 |
Worker 스레드 패턴
시간이 많이 걸리는 I/O 작업은 메인 스레드 차단을 방지하기 위해 Worker 스레드에서 실행됩니다.
DbClient — 데이터베이스 Worker
DbClient는 가장 중요한 Worker로, SQLite 데이터베이스와의 모든 상호작용을 캡슐화합니다:
sequenceDiagram
participant S as Service
participant C as DbClient
participant W as db.worker.ts
participant D as SQLite (WAL)
S->>C: db.someMethod(params)
C->>C: seq++, create Promise
C->>W: postMessage({id: seq, method, params})
W->>D: Execute SQL query
D-->>W: Result
W-->>C: postMessage({id: seq, result})
C->>C: resolve(pending[seq])
C-->>S: Promise<result>
{/* 단순화된 DbClient RPC 패턴 */}
class DbClient extends EventEmitter implements DbRpc {
private worker: Worker;
private seq = 0;
private pending = Map<number, {resolve, reject}>;
async send(method: string, params: unknown): Promise<unknown> {
const id = ++this.seq;
return new Promise((resolve, reject) => {
this.pending.set(id, { resolve, reject });
this.worker.postMessage({ id, method, params });
});
}
async ready(): Promise<void>;
}
주요 설계 포인트:
- 비동기 RPC: 각 호출에 고유한 시퀀스 번호가 부여되며, 요청은
postMessage를 통해 전송됨 - Ready 대기:
await db.ready()는 사용 전에 Worker가 초기화(스키마 생성)를 완료했는지 보장함 - 오류 전달: Worker 오류는 EventEmitter를 통해 상위로 전파됨
Worker 스레드 목록
| Worker 파일 | 목적 | 통신 방식 |
|---|---|---|
db.worker.ts | SQLite 데이터베이스 읽기/쓰기 (100개 이상의 RPC 메서드) | DbClient RPC |
fileSearch.worker.ts | 파일 검색 (퍼지 매칭) | MessagePort |
fileWatcher.worker.ts | 파일 시스템 감시 (chokidar) | MessagePort |
mcp.worker.ts | MCP 서버 프로세스 관리 | MessagePort |
diagnostics.worker.ts | 시스템 진단 데이터 수집 | MessagePort |
project.worker.ts | 프로젝트 파일 인덱스 빌드 | MessagePort |
fileSnapshot.worker.ts | 파일 스냅샷 차분 | MessagePort |
핵심 인프라
LoggerService
Winston 기반으로, 로그 레벨 필터링 및 자동 로그 파일 로테이션을 지원합니다:
{/* 단순화된 LoggerService 인터페이스 */}
class LoggerService {
info(message: string, meta?: Record<string, unknown>): void;
warn(message: string, err?: Error, meta?: Record<string, unknown>): void;
error(message: string, err?: unknown, meta?: Record<string, unknown>): void;
debug(message: string, meta?: Record<string, unknown>): void;
}
- 로그 위치:
{userData}/logs/ - 로테이션 정책: daily-rotate-file, 14일 보관
- 형식: JSON + 타임스탬프
SecurityService / CryptoService
{/* 핵심 암호화 서비스 인터페이스 */}
class SecurityService {
encrypt(plaintext: string): string;
decrypt(ciphertext: string): string;
}
class CryptoService {
deriveKey(password: string, salt: Buffer): Buffer;
encrypt(data: string, key: Buffer): EncryptedData;
decrypt(data: EncryptedData, key: Buffer): string;
}
AppPaths
모든 애플리케이션 디렉토리 경로를 중앙에서 관리합니다:
| 프로퍼티 | 경로 | 목적 |
|---|---|---|
userData | {appData}/elftia/ | 애플리케이션 데이터 루트 |
dbPath | {userData}/elftia.db | SQLite 데이터베이스 |
configDir | {userData}/config/ | 설정 파일 디렉토리 |
resourcesDir | {userData}/resources/ | 미디어 리소스 |
diagnosticsDir | {userData}/diagnostics/ | 진단 데이터 |
logsDir | {userData}/logs/ | 로그 파일 |
관련 파일
| 파일 | 설명 |
|---|---|
packages/desktop/app/main/index.ts | 메인 프로세스 진입점; 모든 서비스 생성 및 시작 |
packages/desktop/app/main/services/routers/index.ts | 라우트 등록 센터, registerAllRouters() |
packages/desktop/app/main/services/routers/BaseRouter.ts | Router 기반 클래스 |
packages/desktop/app/main/ipc/safe-handle.ts | secureHandle IPC 보안 래퍼 |
packages/desktop/app/main/workers/DbClient.ts | 데이터베이스 Worker 클라이언트 |
packages/desktop/app/main/workers/db.worker.ts | 데이터베이스 Worker 구현 |
packages/desktop/app/main/workers/types.ts | Worker RPC 타입 정의 |
packages/desktop/app/main/services/infra/logger/LoggerService.ts | 로깅 서비스 |
packages/desktop/app/main/services/platform/security/SecurityService.ts | 암호화 서비스 |
packages/desktop/app/main/services/infra/paths/paths.ts | 경로 관리 |
packages/desktop/app/main/services/agent-core/engine/EngineDispatcher.ts | 엔진 디스패처 |