본문으로 건너뛰기

oneshim-web

로컬 웹 대시보드 — Axum REST API + React 프론트엔드

크레이트 유형

라이브러리 크레이트 (lib) — oneshim-app에 통합되어 실행됨


📋 개요

oneshim-web은 데스크톱 에이전트의 로컬 웹 대시보드를 제공합니다. Rust 백엔드(Axum)와 React 프론트엔드를 결합하여 브라우저에서 에이전트 상태를 모니터링하고 설정을 관리할 수 있습니다.

주요 특징

기능설명
REST API60개+ 엔드포인트 (메트릭, 프레임, 이벤트, 태그, 검색, 리포트, 자동화 등)
실시간 SSEServer-Sent Events로 실시간 메트릭 스트리밍
React 프론트엔드React 18 + Vite + Tailwind CSS (9페이지)
정적 파일 임베드rust-embed로 빌드 결과 바이너리에 포함
다국어 지원한국어/영어 자동 감지 (i18n, 220개+ 키)
자동화 대시보드자동화 상태, 감사 로그, 워크플로우 프리셋, 실행 통계
E2E 테스트Playwright 기반 72개 테스트

🏗️ 아키텍처


📂 디렉토리 구조

crates/oneshim-web/
├── src/
│ ├── lib.rs # WebServer + AppState (audit_logger 포함)
│ ├── routes.rs # 라우트 정의 (60개+ 엔드포인트)
│ ├── embedded.rs # 정적 파일 서빙 + SPA 라우팅
│ ├── error.rs # ApiError 정의
│ └── handlers/ # REST API 핸들러
│ ├── metrics.rs # 시스템 메트릭
│ ├── processes.rs # 프로세스 정보
│ ├── idle.rs # 유휴 상태
│ ├── sessions.rs # 세션 통계
│ ├── frames.rs # 스크린샷 프레임
│ ├── events.rs # 이벤트 로그
│ ├── stats.rs # 통계 (히트맵 포함)
│ ├── tags.rs # 태그 관리
│ ├── search.rs # 통합 검색
│ ├── reports.rs # 리포트 생성
│ ├── timeline.rs # 통합 타임라인
│ ├── focus.rs # 집중도 분석
│ ├── backup.rs # 백업/복원
│ ├── export.rs # 데이터 내보내기
│ ├── settings.rs # 설정 조회/변경 (자동화/샌드박스/AI 포함)
│ ├── automation.rs # 자동화 API (10개 엔드포인트)
│ └── stream.rs # SSE 실시간 스트림
└── frontend/
├── src/
│ ├── App.tsx # 라우팅 + 레이아웃
│ ├── pages/ # 페이지 컴포넌트 (9개)
│ ├── components/ # 공통 컴포넌트
│ ├── components/ui/ # 디자인 시스템 컴포넌트
│ ├── styles/ # 디자인 토큰 + 변형
│ ├── lib/ # 유틸리티
│ ├── i18n/ # 다국어 번역 (220개+ 키)
│ └── api.ts # API 클라이언트
├── e2e/ # Playwright E2E 테스트
├── playwright.config.ts
└── package.json

🔌 AppState

#[derive(Clone)]
pub struct AppState {
pub storage: Arc<SqliteStorage>,
pub frames_dir: Option<PathBuf>,
pub event_tx: broadcast::Sender<RealtimeEvent>,
pub config_manager: Option<ConfigManager>,
pub audit_logger: Option<Arc<RwLock<AuditLogger>>>,
}

WebServer 빌더

let server = WebServer::new(storage, web_config)
.with_config_manager(config_manager)
.with_audit_logger(audit_logger)
.with_event_tx(event_tx)
.with_frames_dir(frames_dir);

server.run(shutdown_rx).await?;

🌐 REST API 엔드포인트

메트릭 & 모니터링

메서드경로설명
GET/api/metrics시스템 메트릭 조회
GET/api/metrics/history메트릭 히스토리
GET/api/processes프로세스 목록
GET/api/idle유휴 상태 조회
GET/api/sessions세션 통계
GET/api/stats/heatmap활동 히트맵
GET/api/streamSSE 실시간 스트림

프레임 & 이벤트

메서드경로설명
GET/api/frames프레임 목록 (페이지네이션)
GET/api/frames/:id프레임 상세
GET/api/frames/:id/image프레임 이미지
GET/api/events이벤트 목록 (페이지네이션)

태그

메서드경로설명
GET/api/tags모든 태그 조회
POST/api/tags태그 생성
PUT/api/tags/:id태그 수정
DELETE/api/tags/:id태그 삭제
POST/api/frames/:id/tags/:tag_id프레임에 태그 추가
DELETE/api/frames/:id/tags/:tag_id프레임에서 태그 제거

검색 & 리포트

메서드경로설명
GET/api/search통합 검색 (텍스트 + 태그)
GET/api/reports활동 리포트 생성
GET/api/timeline통합 타임라인

집중도 분석

메서드경로설명
GET/api/focus/metrics집중도 메트릭
GET/api/focus/sessions작업 세션
GET/api/focus/interruptions중단 이벤트
GET/api/focus/suggestions로컬 제안
POST/api/focus/suggestions/:id/feedback제안 피드백

설정 & 데이터 관리

메서드경로설명
GET/api/settings설정 조회 (자동화/샌드박스/AI 포함)
POST/api/settings설정 변경
GET/api/backup백업 다운로드
POST/api/backup/restore백업 복원
GET/api/export/:type데이터 내보내기 (JSON/CSV)

자동화 (Automation)

메서드경로설명
GET/api/automation/status자동화 시스템 상태
GET/api/automation/audit감사 로그 조회 (limit, status 필터)
GET/api/automation/policies활성 정책 요약
GET/api/automation/stats실행 통계 (성공/실패/거부/타임아웃)
GET/api/automation/presets프리셋 목록 (내장 + 사용자)
POST/api/automation/presets사용자 프리셋 생성
PUT/api/automation/presets/:id사용자 프리셋 수정
DELETE/api/automation/presets/:id사용자 프리셋 삭제
POST/api/automation/presets/:id/run프리셋 실행

📊 자동화 API DTO

/// 자동화 시스템 상태
pub struct AutomationStatusDto {
pub enabled: bool,
pub sandbox_enabled: bool,
pub sandbox_profile: String,
pub ocr_provider: String,
pub llm_provider: String,
pub external_data_policy: String,
pub pending_audit_entries: usize,
}

/// 감사 로그 엔트리
pub struct AuditEntryDto {
pub entry_id: String,
pub timestamp: String,
pub session_id: String,
pub command_id: String,
pub action_type: String,
pub status: String, // Started | Completed | Failed | Denied | Timeout
pub details: Option<String>,
pub elapsed_ms: Option<u64>,
}

/// 실행 통계
pub struct AutomationStatsDto {
pub total_executions: usize,
pub successful: usize,
pub failed: usize,
pub denied: usize,
pub timeout: usize,
pub avg_elapsed_ms: f64,
}

⚙️ Settings DTO (자동화 관련)

AppSettings에 3개 자동화 섹션 추가:

pub struct AppSettings {
// ... 기존 모니터/비전/알림/프라이버시 설정 ...
pub automation: AutomationSettings,
pub sandbox: SandboxSettings,
pub ai_provider: AiProviderSettings,
}

pub struct AutomationSettings { pub enabled: bool }

pub struct SandboxSettings {
pub enabled: bool,
pub profile: String, // "Permissive" | "Standard" | "Strict"
pub allowed_read_paths: Vec<String>,
pub allowed_write_paths: Vec<String>,
pub allow_network: bool,
pub max_memory_bytes: u64,
pub max_cpu_time_ms: u64,
}

pub struct AiProviderSettings {
pub ocr_provider: String, // "Local" | "Remote"
pub llm_provider: String, // "Local" | "Remote"
pub external_data_policy: String, // "PiiFilterStrict" | "PiiFilterStandard" | "AllowFiltered"
pub fallback_to_local: bool,
pub ocr_api: Option<ExternalApiSettings>,
pub llm_api: Option<ExternalApiSettings>,
}

pub struct ExternalApiSettings {
pub endpoint: String,
pub api_key_masked: String, // GET: 마스킹 / POST: 전체 키
pub model: Option<String>,
pub timeout_secs: u64,
}
API 키 마스킹
  • GET: mask_api_key("sk-1234567890abcdef")"sk...cdef" (앞 2자 + ... + 뒤 4자)
  • POST: 전체 키 수신 시 저장, 마스킹된 값(is_masked_key())이면 기존 키 유지

🎨 프론트엔드 페이지

페이지경로단축키기능
Dashboard/D실시간 메트릭, CPU/Memory 차트, 앱 사용량, 히트맵, 집중도
Timeline/timelineT스크린샷 그리드/리스트, 필터링, 태그, 라이트박스
Search/search통합 검색, 태그 필터, 결과 하이라이팅
Reports/reportsR주간/월간 리포트, 생산성 점수, 차트
Session Replay/replay세션 리플레이
Focus Analytics/focus집중도 분석
Automation/automationA자동화 대시보드
Settings/settingsS설정 (자동화/샌드박스/AI 포함)
Privacy/privacyP개인정보 관리

Automation 페이지

5개 패널로 구성 (React Query 기반):

  1. 상태 카드 — 활성화 여부, 샌드박스 프로필, OCR/LLM 제공자, 대기 감사 항목
  2. 워크플로우 프리셋 — 카테고리별 탭 (생산성/앱 관리/워크플로우/사용자), 프리셋 카드 그리드, 실행/CRUD
  3. 실행 통계 — 성공/실패/거부/타임아웃 카운트 + 평균 소요 시간
  4. 감사 로그 — 테이블 (시각, 명령ID, 액션, 상태 배지, 소요시간), 상태별 필터, 30초 자동 새로고침
  5. 정책 정보 — 현재 적용된 정책 요약

Settings 페이지 (자동화 섹션)

기존 설정에 3개 섹션 추가:

  1. 자동화 — 활성화 토글
  2. 샌드박스 — 활성화, 프로필 드롭다운, 네트워크 허용 토글
  3. AI 제공자 — OCR/LLM 타입 선택, 데이터 정책, 폴백 토글, 외부 API 설정 (type="password")

🎯 디자인 시스템

코드 기반 디자인 시스템으로 TypeScript 타입 안전성을 통해 일관성을 보장합니다.

디자인 토큰 (styles/tokens.ts)

export const colors = {
primary: {
DEFAULT: 'bg-teal-600 dark:bg-teal-500',
hover: 'hover:bg-teal-700 dark:hover:bg-teal-400',
text: 'text-teal-600 dark:text-teal-400',
},
surface: { bg: '...', elevated: '...', border: '...' },
text: { primary: '...', secondary: '...', tertiary: '...' },
semantic: { success: '...', warning: '...', error: '...', info: '...' },
status: { online: '...', offline: '...', idle: '...' },
}

UI 컴포넌트 (components/ui/)

컴포넌트Props설명
Buttonvariant, size, isLoading버튼 (primary/secondary/ghost/danger)
Cardvariant, padding카드 (default/elevated/highlight/interactive)
Inputvariant, inputSize, error입력 필드
Badgecolor, size배지 (7가지 색상)
Selectvariant, selectSize드롭다운
Spinnersize로딩 스피너

🌍 다국어 지원 (i18n)

react-i18next 기반으로 한국어/영어 자동 감지를 지원합니다.

번역 파일

  • i18n/locales/ko.json — 한국어 (220+ 키)
  • i18n/locales/en.json — 영어 (220+ 키)

주요 번역 영역

  • automation.* — 자동화 UI 번역 (40개+)
  • settingsAutomation.* — 자동화 설정 번역 (26개+)
  • 기존 번역 유지 (dashboard, timeline, settings, privacy, search, reports 등)

🧪 테스트

Rust 테스트 (78개)

cargo test -p oneshim-web
  • API 핸들러 테스트
  • 라우트 테스트
  • 에러 핸들링 테스트
  • 자동화 DTO 직렬화
  • 설정 매핑 (자동화/샌드박스/AI)

E2E 테스트 (72개)

cd crates/oneshim-web/frontend
pnpm test:e2e # 전체 실행
pnpm test:e2e:headed # 브라우저 표시
pnpm test:e2e:ui # Playwright UI 모드
파일테스트 수검증 영역
navigation.spec.ts9네비게이션, 키보드 단축키
dashboard.spec.ts8메트릭 카드, 차트, 연결 상태
timeline.spec.ts8필터링, 뷰 모드, 키보드
settings.spec.ts13설정 폼, 저장, 내보내기
privacy.spec.ts13데이터 삭제, 백업/복원
search.spec.ts10검색 폼, 태그 필터
reports.spec.ts11기간 선택, 차트, 통계

⚙️ 설정

WebConfig

oneshim-coreAppConfig에 포함된 웹 서버 설정:

[web]
enabled = true
port = 9090
allow_external = false
옵션설명기본값
enabled웹 서버 활성화true
port포트 번호9090
allow_external외부 접속 허용false

자동 포트 찾기

포트 충돌 시 다음 포트를 자동으로 시도합니다 (최대 10개).

9090 → 9091 → 9092 → ... → 9099

🔧 빌드

프론트엔드 빌드

cd crates/oneshim-web/frontend
pnpm install
pnpm build

전체 빌드 (프론트엔드 임베드)

# 프론트엔드 빌드 후 Rust 빌드
./scripts/build-frontend.sh
cargo build --release -p oneshim-app

rust-embedfrontend/dist/ 디렉토리를 바이너리에 포함합니다.


📦 의존성

Rust

크레이트버전용도
axum0.7HTTP 서버
tower-http0.6CORS, 로깅
rust-embed8정적 파일 임베드
mime_guess2Content-Type 감지
tokio1비동기 런타임

Frontend

패키지버전용도
react18UI 라이브러리
vite6번들러
tailwindcss3CSS 프레임워크
recharts2차트
i18next24다국어
@playwright/test1E2E 테스트
clsx + tailwind-merge-클래스 병합

관련 문서: