asyouplz_SpeechNote/docs/project-structure.md
asyouplz 7f776af999 Initial commit: Obsidian Speech-to-Text Plugin
- Set up project structure and architecture
- Implement core transcription services with OpenAI Whisper API
- Add comprehensive UI components and settings
- Create documentation in Korean and English
- Establish testing framework and examples

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-25 20:00:43 +09:00

13 KiB

프로젝트 구조 문서 (Project Structure Documentation)

목차

  1. 개요
  2. 디렉토리 구조
  3. 계층별 상세 설명
  4. 모듈 간 의존성
  5. 파일 네이밍 컨벤션
  6. 코드 구성 원칙

개요

이 프로젝트는 클린 아키텍처(Clean Architecture) 원칙을 따르는 계층형 구조로 설계되었습니다. 각 계층은 명확한 책임을 가지며, 의존성은 항상 안쪽 방향(도메인 중심)으로 향합니다.

아키텍처 특징

  • 관심사의 분리: 각 계층은 독립적인 책임을 가짐
  • 의존성 역전: 고수준 모듈이 저수준 모듈에 의존하지 않음
  • 테스트 용이성: 각 계층을 독립적으로 테스트 가능
  • 확장성: 새로운 기능을 기존 코드 수정 없이 추가 가능

디렉토리 구조

SpeechNote/
├── 📦 src/                              # 소스 코드 루트
│   ├── 🎯 main.ts                       # 플러그인 진입점
│   │
│   ├── 💼 application/                  # 응용 계층
│   │   ├── EventManager.ts              # 이벤트 발행/구독 관리
│   │   └── StateManager.ts              # 전역 상태 관리
│   │
│   ├── 🧠 core/                         # 핵심 비즈니스 로직 계층
│   │   └── transcription/               # 음성 변환 도메인
│   │       ├── AudioProcessor.ts        # 오디오 파일 처리 로직
│   │       ├── TextFormatter.ts         # 텍스트 포맷팅 로직
│   │       └── TranscriptionService.ts  # 변환 서비스 조정자
│   │
│   ├── 📊 domain/                       # 도메인 모델 계층
│   │   └── models/
│   │       └── Settings.ts              # 설정 도메인 모델
│   │
│   ├── 🔌 infrastructure/               # 인프라스트럭처 계층
│   │   ├── api/
│   │   │   └── WhisperService.ts        # OpenAI Whisper API 클라이언트
│   │   ├── logging/
│   │   │   └── Logger.ts                # 로깅 시스템
│   │   └── storage/
│   │       └── SettingsManager.ts       # 설정 영속성 관리
│   │
│   ├── 🛠️ utils/                        # 유틸리티 함수
│   │   └── ErrorHandler.ts              # 중앙 에러 처리
│   │
│   └── 📝 types/                        # TypeScript 타입 정의
│       └── index.ts                     # 공통 타입 및 인터페이스
│
├── 📚 docs/                             # 프로젝트 문서
│   ├── setup-guide.md                   # 개발 환경 설정 가이드
│   ├── project-structure.md             # 프로젝트 구조 문서 (현재 파일)
│   └── api-reference.md                 # API 레퍼런스
│
├── 🏗️ architecture/                     # 아키텍처 문서
│   ├── system-design.md                 # 시스템 설계 문서
│   └── diagrams/                        # 아키텍처 다이어그램
│       ├── 01-overall-architecture.mmd  # 전체 아키텍처
│       ├── 02-component-dependencies.mmd # 컴포넌트 의존성
│       ├── 03-data-flow.mmd            # 데이터 흐름
│       └── ...
│
├── 📋 guidelines/                       # 개발 가이드라인
│   └── development-guide.md             # 개발 가이드
│
├── 🧪 tests/                            # 테스트 코드 (준비 중)
│   ├── unit/                            # 단위 테스트
│   ├── integration/                     # 통합 테스트
│   └── e2e/                            # End-to-End 테스트
│
├── ⚙️ 설정 파일
│   ├── manifest.json                    # Obsidian 플러그인 메타데이터
│   ├── package.json                     # Node.js 프로젝트 설정
│   ├── tsconfig.json                    # TypeScript 컴파일러 설정
│   ├── esbuild.config.mjs               # ESBuild 번들러 설정
│   └── jest.config.js                   # Jest 테스트 프레임워크 설정
│
└── 📄 루트 파일
    ├── README.md                        # 프로젝트 소개 및 사용법
    ├── CONTRIBUTING.md                  # 기여 가이드라인
    ├── LICENSE                          # 라이선스 정보
    └── styles.css                       # 플러그인 스타일시트

계층별 상세 설명

1. Main Entry Point (main.ts)

책임: 플러그인 생명주기 관리

  • Obsidian Plugin 클래스 확장
  • 서비스 초기화 및 의존성 주입
  • 명령어 등록
  • 설정 탭 등록
  • 이벤트 핸들러 설정

2. Application Layer (application/)

책임: 애플리케이션 흐름 제어 및 조정

EventManager.ts

  • 이벤트 기반 통신 구현
  • 발행-구독 패턴 제공
  • 컴포넌트 간 느슨한 결합 유지

StateManager.ts

  • 전역 상태 관리
  • 상태 변경 구독 메커니즘
  • 불변성 보장

3. Core Business Logic (core/)

책임: 핵심 비즈니스 규칙 구현

transcription/AudioProcessor.ts

  • 오디오 파일 검증
  • 파일 형식 변환
  • 메타데이터 추출
  • 크기 제한 확인

transcription/TextFormatter.ts

  • 변환된 텍스트 포맷팅
  • 타임스탬프 처리
  • 템플릿 적용
  • 마크다운 포맷팅

transcription/TranscriptionService.ts

  • 변환 프로세스 조정
  • 비즈니스 로직 실행
  • 에러 처리 및 재시도
  • 진행 상태 관리

4. Domain Models (domain/)

책임: 비즈니스 엔티티 정의

models/Settings.ts

  • 설정 데이터 모델
  • 기본값 정의
  • 유효성 검증 규칙

5. Infrastructure Layer (infrastructure/)

책임: 외부 시스템과의 통합

api/WhisperService.ts

  • OpenAI Whisper API 통신
  • HTTP 요청/응답 처리
  • 인증 관리
  • Rate limiting

logging/Logger.ts

  • 로그 레벨 관리
  • 콘솔 출력
  • 디버그 정보 기록

storage/SettingsManager.ts

  • 설정 영속성
  • Obsidian 저장소 통합
  • 데이터 직렬화/역직렬화

6. Utilities (utils/)

책임: 공통 유틸리티 함수

ErrorHandler.ts

  • 중앙화된 에러 처리
  • 에러 분류 및 로깅
  • 사용자 친화적 메시지 변환

7. Type Definitions (types/)

책임: TypeScript 타입 정의

index.ts

  • 공통 인터페이스
  • 타입 별칭
  • 열거형 정의
  • 제네릭 타입

모듈 간 의존성

의존성 방향

main.ts
   ↓
application/ ← → infrastructure/
   ↓               ↓
core/  ←────────────┘
   ↓
domain/
   ↑
types/ (모든 계층에서 참조)

의존성 규칙

  1. 내부 방향 의존성: 외부 계층은 내부 계층에 의존
  2. 인터페이스 의존성: 구현이 아닌 추상화에 의존
  3. 순환 의존성 금지: 모듈 간 순환 참조 방지
  4. 도메인 독립성: 도메인 계층은 외부 의존성 없음

주요 의존성 관계

// main.ts → application/
import { EventManager } from './application/EventManager';
import { StateManager } from './application/StateManager';

// main.ts → core/
import { TranscriptionService } from './core/transcription/TranscriptionService';

// core/ → domain/
import { Settings } from '../../domain/models/Settings';

// infrastructure/ → types/
import { WhisperOptions, WhisperResponse } from '../../types';

파일 네이밍 컨벤션

일반 규칙

파일 유형 네이밍 규칙 예시
클래스/서비스 PascalCase TranscriptionService.ts
유틸리티 PascalCase ErrorHandler.ts
타입/인터페이스 PascalCase Settings.ts
설정 파일 kebab-case esbuild.config.mjs
문서 kebab-case setup-guide.md
인덱스 파일 lowercase index.ts

디렉토리 네이밍

  • 소문자: 모든 소스 코드 디렉토리
  • 의미있는 이름: 역할을 명확히 표현
  • 단수형 사용: model 대신 models 제외

코드 구성 원칙

1. 단일 책임 원칙 (SRP)

// ✅ 좋은 예: 하나의 책임만 가짐
export class AudioProcessor {
  async validateFormat(file: TFile): Promise<boolean> { }
  async extractMetadata(buffer: ArrayBuffer): Promise<AudioMetadata> { }
}

// ❌ 나쁜 예: 여러 책임을 가짐
export class AudioHandler {
  async processAudio() { }
  async saveSettings() { }
  async sendToAPI() { }
}

2. 의존성 주입 (DI)

// ✅ 좋은 예: 의존성 주입
export class TranscriptionService {
  constructor(
    private whisperService: WhisperService,
    private audioProcessor: AudioProcessor,
    private textFormatter: TextFormatter
  ) {}
}

// ❌ 나쁜 예: 직접 생성
export class TranscriptionService {
  private whisperService = new WhisperService();
}

3. 인터페이스 분리

// ✅ 좋은 예: 작고 구체적인 인터페이스
interface ITranscriber {
  transcribe(audio: ArrayBuffer): Promise<string>;
}

interface ICancellable {
  cancel(): void;
}

// ❌ 나쁜 예: 거대한 인터페이스
interface IService {
  transcribe(): Promise<string>;
  cancel(): void;
  save(): void;
  load(): void;
  validate(): boolean;
}

4. 모듈 구성

// 각 모듈의 구조
export class ModuleName {
  // 1. Static 멤버
  static readonly VERSION = '1.0.0';
  
  // 2. Private 필드
  private config: Config;
  
  // 3. Public 필드
  public status: Status;
  
  // 4. 생성자
  constructor() {}
  
  // 5. Public 메서드
  public async process(): Promise<void> {}
  
  // 6. Private 메서드
  private validate(): boolean {}
  
  // 7. Static 메서드
  static create(): ModuleName {}
}

5. 에러 처리

// 각 계층별 에러 처리
try {
  // 비즈니스 로직
  const result = await this.process();
} catch (error) {
  // 1. 로깅
  this.logger.error('Processing failed', error);
  
  // 2. 에러 변환
  if (error instanceof NetworkError) {
    throw new ServiceError('Connection failed');
  }
  
  // 3. 상위 전파
  throw error;
}

테스트 구조

테스트 파일 위치

tests/
├── unit/                     # 단위 테스트
│   ├── core/
│   │   └── AudioProcessor.test.ts
│   ├── domain/
│   │   └── Settings.test.ts
│   └── utils/
│       └── ErrorHandler.test.ts
├── integration/              # 통합 테스트
│   └── TranscriptionFlow.test.ts
└── e2e/                     # End-to-End 테스트
    └── PluginLifecycle.test.ts

테스트 네이밍 컨벤션

  • 테스트 파일: {ComponentName}.test.ts
  • 테스트 설명: should {expected behavior} when {condition}

빌드 아티팩트

생성되는 파일

파일 설명 위치
main.js 번들된 JavaScript 루트 디렉토리
main.js.map 소스맵 (개발용) 루트 디렉토리
styles.css 스타일시트 루트 디렉토리

무시되는 파일 (.gitignore)

node_modules/
main.js
main.js.map
.DS_Store
*.log
.env

모범 사례

1. 새 기능 추가 시

  1. 적절한 계층 결정
  2. 인터페이스 먼저 정의
  3. 테스트 작성
  4. 구현
  5. 문서 업데이트

2. 파일 크기 관리

  • 단일 파일: 최대 300줄
  • 단일 함수: 최대 50줄
  • 단일 클래스: 하나의 책임

3. 임포트 순서

// 1. 외부 라이브러리
import { Plugin } from 'obsidian';

// 2. 내부 모듈 (절대 경로)
import { TranscriptionService } from 'src/core/TranscriptionService';

// 3. 상대 경로 임포트
import { Settings } from './Settings';

// 4. 타입 임포트
import type { TranscriptionOptions } from '../types';

개발 워크플로우

1. 기능 개발 프로세스

feature/
├── 1. 요구사항 분석
├── 2. 아키텍처 설계
├── 3. 인터페이스 정의
├── 4. 테스트 작성 (TDD)
├── 5. 구현
├── 6. 리팩토링
└── 7. 문서화

2. 코드 리뷰 체크리스트

  • 아키텍처 원칙 준수
  • 테스트 커버리지 80% 이상
  • 문서 업데이트
  • 타입 안정성
  • 에러 처리
  • 성능 고려사항

문서 업데이트

이 문서는 프로젝트 구조가 변경될 때마다 업데이트되어야 합니다:

  1. 새 모듈 추가 시
  2. 디렉토리 구조 변경 시
  3. 의존성 관계 변경 시
  4. 네이밍 컨벤션 변경 시

최종 업데이트: 2025-08-22 버전: 1.0.0