cc-switch 내부 작동 원리와 아키텍처 깊이 들여다보기
cc-switch는 성능과 메모리 효율성을 극대화하기 위해 Tauri 2 프레임워크와 Rust 언어를 기반으로 구축되었어요. 프론트엔드는 React와 TypeScript로 구성되어 직관적인 사용자 경험을 제공하고, 백엔드는 Rust 가 핵심 로직을 담당하여 리소스 점유율을 수 메가바이트 수준으로 낮게 유지해요.
로컬 프록시 게이트웨이와 모델 매핑 엔진
cc-switch의 주요 기능 중 하나는 앱 내부에 구현된 로컬 프록시 게이트웨이(Local Proxy Gateway)예요. 일부 AI 에디터(예: Claude Desktop)는 공식 Anthropic 모델 이름(claude-3-5-sonnet 등)만을 강제로 요구하는 제약이 있어요. cc-switch 프록시 게이트웨이는 이 요청을 중간에서 수신하여 사용자가 지정한 업스트림 프로바이더의 모델 ID로 유연하게 변환(Model Mapping)해 줘요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
sequenceDiagram
autonumber
actor User as 개발자
participant App as AI 클라이언트 앱
participant Proxy as cc-switch 로컬 프록시
participant Model as 업스트림 API 서버
User->>App: 코딩 요청 전달
App->>Proxy: 요청 발송 (기본 모델 ID)
Proxy->>Proxy: 모델 매핑 및 헤더 재구성
Proxy->>Model: 대상 프로바이더 규격으로 변환 전달
Model-->>Proxy: 스트리밍 응답 반환
Proxy-->>App: 클라이언트 맞춤 형식으로 전달
App-->>User: 결과 출력
데이터 모델 및 저장소 구조
cc-switch는 내부 구성을 안전하게 수용하기 위해 SQLite 데이터베이스를 채택하고 있어요. 앱 버전 업그레이드 시 마이그레이션 파이프라인(예: v9에서 v10으로의 마이그레이션)이 자동으로 작동하여 데이터 손실 없이 구성을 보존해요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
erDiagram
APP_CONFIG {
string app_id
string active_provider_id
string current_version
}
PROVIDER_PRESET {
string provider_id
string provider_name
string base_url
string api_key
}
PROXY_RULE {
string rule_id
string source_model
string target_model
}
MCP_SERVER {
string server_id
string server_name
string command_path
}
APP_CONFIG ||--o{ PROVIDER_PRESET : uses
APP_CONFIG ||--o{ PROXY_RULE : applies
APP_CONFIG ||--o{ MCP_SERVER : connects
원자적 파일 쓰기와 트랜잭션 안전성
설정 파일을 수정하는 도중 컴퓨터가 꺼지거나 오류가 발생하면 CLI 도구 전체가 동작 불능 상태에 빠질 수 있어요. cc-switch는 이를 방지하기 위해 원자적 쓰기(Atomic Write) 패턴을 사용해요. 새로운 설정을 적용할 때 임시 파일(.tmp)에 먼저 기록하고, 파싱 및 검증을 통과한 경우에만 기존 파일을 교체(Replace)하는 방식이에요. 문제 발생 시 이전 정상 상태로 즉시 롤백돼요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
stateDiagram-v2
[*] --> Idle
Idle --> Modifying : 프로바이더 전환 요청
Modifying --> Validating : API 지연 시간 및 스키마 검증
Validating --> WritingTemp : 임시 파일 생성 및 기록
WritingTemp --> AtomicReplace : 원자적 교체 실행
AtomicReplace --> Idle : 전환 완료
WritingTemp --> Rollback : 검증 실패
Rollback --> Idle : 이전 복원 완료
백엔드 모듈 및 계층 구조
Rust 코어는 각 역할에 맞게 명확히 모듈화되어 있어 높은 안정성과 테스트 커버리지를 보장해요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
classDiagram
class CODE_APP {
+String app_name
+String config_path
+read_config()
+write_config()
}
class CODE_PROVIDER {
+String provider_id
+String base_url
+String api_key
+test_latency()
}
class CODE_PROXY {
+u16 port
+bool circuit_breaker
+forward_request()
}
class CODE_STORAGE {
+String db_path
+atomic_commit()
}
CODE_APP --> CODE_PROVIDER
CODE_PROXY --> CODE_PROVIDER
CODE_APP --> CODE_STORAGE
생태계 클라이언트 비중
cc-switch가 관리하는 대표적인 CLI 및 AI 에디터 생태계 비중은 다음과 같이 다양하게 분포되어 있어요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
pie title 지원 AI 클라이언트 생태계 비중
"Claude Code" : 30
"Claude Desktop" : 20
"OpenAI Codex" : 15
"Gemini CLI" : 15
"OpenCode 및 OpenClaw" : 12
"Hermes Agent 및 기타" : 8
서킷 브레이커와 자동 페일오버 시스템
지정된 프로바이더 API에서 5xx 서버 오류나 네트워크 타임아웃이 발생하면, cc-switch의 서킷 브레이커(Circuit Breaker)가 상태를 차단하고 미리 설정된 보조 프로바이더 엔드포인트로 요청을 우회 처리해요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
flowchart LR
A["요청 접수"] --> B{"정상 상태인가"}
B -- 예 --> C["주 프로바이더 처리"]
B -- 아니오 --> D["서킷 브레이커 작동"]
D --> E["보조 프로바이더 우회"]
C -- 성공 --> F["응답 반환"]
E -- 성공 --> F
C -- 실패 --> G["오류 기록 및 차단"]
G --> E