Skip to main content
Glama

WhaTap MXQL CLI

by devload
MODULE_PLAN.md16.7 kB
# WhaTap MXQL CLI - 모듈 구성 및 구현 계획 ## 📊 모듈 의존성 다이어그램 ``` ┌─────────────────────────────────────────────────────────────┐ │ Application Layer │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ CLI App │ │ MCP Server │ │ │ │ (commands) │ │ (tools) │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ └─────────┼──────────────────────────────┼─────────────────────┘ │ │ ├──────────────────────────────┤ │ │ ┌─────────▼──────────────────────────────▼─────────────────────┐ │ Core Layer (공유) │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ MxqlExecutor │────────▶│ WhatapClient │ │ │ │ (쿼리 실행 헬퍼) │ │ (API 호출) │ │ │ └──────────────────┘ └────────┬─────────┘ │ │ │ │ │ ┌─────────▼──────────┐ │ │ │ AuthManager │ │ │ │ (인증 관리) │ │ │ └─────────┬──────────┘ │ │ │ │ │ ┌─────────▼──────────┐ │ │ │ SessionStore │ │ │ │ (세션 저장소) │ │ │ └────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ## 🏗️ 모듈 구성 상세 ### Layer 1: 기반 모듈 (의존성 없음) #### 1. **Types** (`src/core/types/index.ts`) - 공통 타입 정의 - 인터페이스 선언 - **의존성**: 없음 - **사용처**: 모든 모듈 ```typescript // 예시 export interface LoginCredentials { email: string; password: string; serviceUrl?: string; } export interface Session { email: string; accountId: number; cookies: { wa: string; jsessionid: string }; apiToken?: string; serviceUrl: string; createdAt: Date; expiresAt: Date; } ``` #### 2. **SessionStore** (`src/core/auth/SessionStore.ts`) - 세션 암호화 저장/로드 - 파일 시스템 I/O - **의존성**: Types만 - **사용처**: AuthManager **핵심 기능**: - `save(session: Session)`: 세션 암호화 후 파일 저장 - `load(): Promise<Session | null>`: 파일에서 세션 복원 - `clear()`: 세션 파일 삭제 ### Layer 2: 인증 모듈 #### 3. **AuthManager** (`src/core/auth/AuthManager.ts`) - WhaTap 인증 로직 (3단계) - 세션 관리 - **의존성**: SessionStore, Types - **사용처**: WhatapClient, CLI, MCP **핵심 기능**: - `login(credentials)`: 로그인 수행 (CSRF → Web → Mobile) - `loadSession()`: 저장된 세션 복원 - `logout()`: 로그아웃 - `isAuthenticated()`: 인증 상태 확인 - `getCookieHeader()`: 쿠키 헤더 문자열 반환 ### Layer 3: API 모듈 #### 4. **WhatapClient** (`src/core/api/WhatapClient.ts`) - WhaTap REST API 호출 - Axios 래퍼 - **의존성**: AuthManager, Types - **사용처**: MxqlExecutor, CLI, MCP **핵심 기능**: - `executeMxql(request)`: MXQL 쿼리 실행 - `getProjects()`: 프로젝트 목록 조회 - `getProject(pcode)`: 프로젝트 상세 조회 #### 5. **MxqlExecutor** (`src/core/api/MxqlExecutor.ts`) - MXQL 쿼리 실행 편의 기능 - 시간 범위 자동 설정 - **의존성**: WhatapClient, Types - **사용처**: CLI, MCP **핵심 기능**: - `execute(options)`: MXQL 쿼리 실행 (편의 메서드) - `executeFromFile(pcode, filePath)`: 파일에서 쿼리 읽어서 실행 ### Layer 4: 애플리케이션 레이어 #### 6. **CLI Commands** (`src/cli/commands/*.ts`) - 사용자 명령어 처리 - **의존성**: 모든 Core 모듈 #### 7. **MCP Tools** (`src/mcp/tools/*.ts`) - MCP Tool 핸들러 - **의존성**: 모든 Core 모듈 --- ## 🔢 구현 순서 및 테스트 전략 ### Phase 1: 프로젝트 초기화 **목표**: 개발 환경 구축 ```bash whatap-mxql-cli/ ├── package.json ├── tsconfig.json ├── jest.config.js ├── .gitignore └── README.md ``` **작업**: 1. ✅ Node.js 프로젝트 초기화 2. ✅ TypeScript 설정 3. ✅ Jest 테스트 설정 4. ✅ 디렉토리 구조 생성 **검증**: - `npm run build` 성공 - `npm test` 실행 가능 --- ### Phase 2: Types 모듈 **파일**: `src/core/types/index.ts` **구현 내용**: - Session 인터페이스 - LoginCredentials 인터페이스 - MxqlRequest, MxqlResponse 인터페이스 - Project 인터페이스 **테스트**: 타입 정의만 있으므로 컴파일 테스트만 수행 --- ### Phase 3: SessionStore 모듈 **파일**: - `src/core/auth/SessionStore.ts` - `test/core/auth/SessionStore.test.ts` **구현 순서**: 1. 기본 구조 (생성자, 파일 경로) 2. 암호화 키 생성/로드 3. 암호화/복호화 메서드 4. save/load/clear 메서드 **테스트 시나리오**: ```typescript describe('SessionStore', () => { test('새 세션을 저장할 수 있다', async () => { const store = new SessionStore(); const session = { /* ... */ }; await store.save(session); // 파일이 생성되었는지 확인 }); test('저장된 세션을 로드할 수 있다', async () => { const store = new SessionStore(); const session = { /* ... */ }; await store.save(session); const loaded = await store.load(); expect(loaded).toEqual(session); }); test('만료된 세션은 null을 반환한다', async () => { const store = new SessionStore(); const expiredSession = { /* ... */ expiresAt: new Date(Date.now() - 1000) // 과거 }; await store.save(expiredSession); const loaded = await store.load(); expect(loaded).toBeNull(); }); test('세션을 삭제할 수 있다', async () => { const store = new SessionStore(); await store.save({ /* ... */ }); await store.clear(); const loaded = await store.load(); expect(loaded).toBeNull(); }); test('암호화된 데이터는 평문이 아니다', async () => { const store = new SessionStore(); const session = { email: 'test@example.com', /* ... */ }; await store.save(session); const fs = require('fs/promises'); const encrypted = await fs.readFile(store.sessionFile, 'utf-8'); expect(encrypted).not.toContain('test@example.com'); }); }); ``` **검증**: - ✅ 모든 테스트 통과 - ✅ 코드 커버리지 90% 이상 --- ### Phase 4: AuthManager 모듈 **파일**: - `src/core/auth/AuthManager.ts` - `test/core/auth/AuthManager.test.ts` **구현 순서**: 1. 기본 구조 (생성자, SessionStore 주입) 2. `getCsrfToken()` - CSRF 토큰 획득 3. `webLogin()` - 웹 로그인 4. `getMobileToken()` - API 토큰 획득 5. `login()` - 전체 로그인 흐름 6. `loadSession()`, `logout()`, `isAuthenticated()` **테스트 시나리오**: ```typescript describe('AuthManager', () => { // Mock SessionStore // Mock HTTP 요청 (axios-mock-adapter 사용) test('CSRF 토큰을 가져올 수 있다', async () => { // Mock GET /account/login?lang=en // HTML 파싱 테스트 }); test('웹 로그인을 수행할 수 있다', async () => { // Mock POST /account/login // 쿠키 추출 테스트 }); test('모바일 API 토큰을 가져올 수 있다', async () => { // Mock POST /mobile/api/login }); test('전체 로그인 흐름이 성공한다', async () => { // 3단계 모두 Mock const authManager = new AuthManager(mockSessionStore); const session = await authManager.login({ email: 'test@example.com', password: 'password123' }); expect(session.accountId).toBeDefined(); expect(session.apiToken).toBeDefined(); }); test('잘못된 비밀번호로 로그인 실패', async () => { // Mock 401 response await expect(authManager.login({ /* ... */ })) .rejects.toThrow(); }); test('저장된 세션을 복원할 수 있다', async () => { // SessionStore.load() Mock }); test('세션이 만료되면 인증되지 않음', async () => { // 만료된 세션 Mock await authManager.loadSession(); expect(authManager.isAuthenticated()).toBe(false); }); }); ``` **검증**: - ✅ 모든 테스트 통과 - ✅ 실제 WhaTap API로 통합 테스트 (선택적) - ✅ 코드 커버리지 85% 이상 --- ### Phase 5: WhatapClient 모듈 **파일**: - `src/core/api/WhatapClient.ts` - `test/core/api/WhatapClient.test.ts` **구현 순서**: 1. 기본 구조 (Axios 인스턴스 생성) 2. 쿠키 인터셉터 설정 3. `executeMxql()` - MXQL 쿼리 실행 4. `getProjects()` - 프로젝트 목록 5. `getProject()` - 프로젝트 상세 **테스트 시나리오**: ```typescript describe('WhatapClient', () => { // Mock AuthManager // Mock Axios test('MXQL 쿼리를 실행할 수 있다', async () => { // Mock POST /yard/api/flush const client = new WhatapClient(mockAuthManager); const result = await client.executeMxql({ type: 'mxql', pcode: 12345, params: { mql: 'CATEGORY app_counter', /* ... */ }, path: 'text' }); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); }); test('요청 시 쿠키 헤더가 포함된다', async () => { // Axios 인터셉터 검증 }); test('프로젝트 목록을 가져올 수 있다', async () => { // Mock GET /v2/project/list }); test('인증되지 않으면 에러를 던진다', async () => { // AuthManager.isAuthenticated() = false await expect(client.executeMxql({ /* ... */ })) .rejects.toThrow('Not authenticated'); }); test('API 에러를 적절히 처리한다', async () => { // Mock 500 response }); }); ``` **검증**: - ✅ 모든 테스트 통과 - ✅ 실제 API 호출 통합 테스트 (선택적) - ✅ 코드 커버리지 85% 이상 --- ### Phase 6: MxqlExecutor 모듈 **파일**: - `src/core/api/MxqlExecutor.ts` - `test/core/api/MxqlExecutor.test.ts` **구현 순서**: 1. 기본 구조 (WhatapClient 주입) 2. `execute()` - 시간 범위 자동 설정 3. `executeFromFile()` - 파일에서 쿼리 읽기 **테스트 시나리오**: ```typescript describe('MxqlExecutor', () => { // Mock WhatapClient test('기본 시간 범위로 쿼리를 실행한다', async () => { const executor = new MxqlExecutor(mockClient); const result = await executor.execute({ pcode: 12345, mql: 'CATEGORY app_counter' // stime, etime 없음 → 자동 설정 }); expect(result.data).toBeDefined(); expect(result.executionTimeMs).toBeGreaterThan(0); }); test('커스텀 시간 범위를 사용할 수 있다', async () => { const result = await executor.execute({ pcode: 12345, mql: 'CATEGORY app_counter', stime: Date.now() - 60000, etime: Date.now() }); // ... }); test('파일에서 쿼리를 읽어서 실행한다', async () => { // Mock fs.readFile const result = await executor.executeFromFile(12345, 'query.mql'); expect(result.data).toBeDefined(); }); test('실행 시간을 측정한다', async () => { const result = await executor.execute({ /* ... */ }); expect(result.executionTimeMs).toBeGreaterThan(0); }); }); ``` **검증**: - ✅ 모든 테스트 통과 - ✅ 코드 커버리지 90% 이상 --- ## 📦 구현 단계별 체크리스트 ### ✅ Phase 1: 프로젝트 초기화 - [ ] package.json 생성 - [ ] TypeScript 설정 - [ ] Jest 설정 - [ ] 디렉토리 구조 생성 - [ ] README.md 작성 ### ⏳ Phase 2: Types - [ ] 인터페이스 정의 - [ ] 타입 컴파일 확인 ### ⏳ Phase 3: SessionStore - [ ] SessionStore 클래스 구현 - [ ] 암호화/복호화 구현 - [ ] 테스트 작성 (5개) - [ ] 테스트 통과 확인 - [ ] 코드 리뷰 ### ⏳ Phase 4: AuthManager - [ ] AuthManager 클래스 기본 구조 - [ ] getCsrfToken() 구현 - [ ] webLogin() 구현 - [ ] getMobileToken() 구현 - [ ] login() 전체 흐름 구현 - [ ] loadSession(), logout() 구현 - [ ] 테스트 작성 (8개) - [ ] 테스트 통과 확인 - [ ] 실제 API 통합 테스트 (선택) - [ ] 코드 리뷰 ### ⏳ Phase 5: WhatapClient - [ ] WhatapClient 클래스 기본 구조 - [ ] Axios 설정 및 인터셉터 - [ ] executeMxql() 구현 - [ ] getProjects() 구현 - [ ] getProject() 구현 - [ ] 테스트 작성 (6개) - [ ] 테스트 통과 확인 - [ ] 실제 API 통합 테스트 (선택) - [ ] 코드 리뷰 ### ⏳ Phase 6: MxqlExecutor - [ ] MxqlExecutor 클래스 구현 - [ ] execute() 구현 - [ ] executeFromFile() 구현 - [ ] 테스트 작성 (4개) - [ ] 테스트 통과 확인 - [ ] 코드 리뷰 --- ## 🧪 테스트 전략 ### 단위 테스트 - **프레임워크**: Jest - **Mock 라이브러리**: jest.mock, axios-mock-adapter - **커버리지 목표**: 85% 이상 ### 통합 테스트 - 실제 WhaTap API 호출 (선택적) - 환경 변수로 테스트 계정 설정 ### E2E 테스트 - CLI 구현 후 진행 - 실제 명령어 실행 테스트 --- ## 📋 각 Phase 완료 기준 각 Phase는 다음 조건을 만족해야 완료: 1. ✅ 코드 구현 완료 2. ✅ 테스트 작성 완료 3. ✅ 모든 테스트 통과 4. ✅ 코드 커버리지 목표 달성 5. ✅ 타입 체크 통과 (`tsc --noEmit`) 6. ✅ Lint 통과 (eslint) 7. ✅ 다음 Phase로 진행 가능한 상태 --- ## 🔄 작업 플로우 각 모듈당: 1. **설계 확인** (5분) - 인터페이스 확인 - 의존성 확인 2. **구현** (30-60분) - 코드 작성 - 주석 추가 3. **테스트 작성** (20-40분) - 테스트 케이스 작성 - Mock 설정 4. **테스트 실행** (5분) - `npm test` - 커버리지 확인 5. **수정 및 재테스트** (필요시) 6. **코드 리뷰** (10분) - 코드 품질 확인 - 문서화 확인 7. **다음 모듈로 진행** --- ## 예상 시간 | Phase | 예상 시간 | |-------|----------| | Phase 1: 프로젝트 초기화 | 30분 | | Phase 2: Types | 15분 | | Phase 3: SessionStore | 1.5시간 | | Phase 4: AuthManager | 2-3시간 | | Phase 5: WhatapClient | 1.5시간 | | Phase 6: MxqlExecutor | 1시간 | | **총합** | **7-8시간** | --- ## 다음 단계 현재: **Phase 1 시작 준비 완료** 질문: 1. 프로젝트 이름: `whatap-mxql-cli` 괜찮으신가요? 2. 테스트는 실제 WhaTap API를 호출할 수 있는 환경이 있나요? - Yes → 통합 테스트 포함 - No → Mock만으로 진행 준비되셨으면 **Phase 1 (프로젝트 초기화)**부터 시작하겠습니다!

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/devload/whatap-mxql-cli'

If you have feedback or need assistance with the MCP directory API, please join our Discord server