# 모바일 직접 녹음 설계

## 1. 목적

사용자가 휴대폰에서 별도 앱 없이 브라우저로 직접 음성을 녹음하고, 녹음 파일을 서버에 업로드해 업무 입력으로 처리한다.

MVP에서 음성 입력은 파일 첨부가 아니라 모바일 브라우저 직접 녹음을 기본 흐름으로 한다.

## 2. 기본 흐름

```text
녹음 권한 요청
-> 녹음 시작
-> 녹음 중 시간 표시
-> 녹음 종료
-> 로컬 미리듣기
-> 서버 업로드
-> 음성 텍스트 변환
-> 변환 텍스트 확인
-> AI 업무 분석
-> 저장 또는 확인 필요
```

## 3. 브라우저 구현 방식

모바일 브라우저에서는 `MediaRecorder` API를 우선 사용한다.

기본 흐름은 다음과 같다.

- `navigator.mediaDevices.getUserMedia({ audio: true })`로 마이크 권한 요청
- `MediaRecorder`로 녹음 시작
- 녹음 데이터를 `Blob`으로 생성
- `FormData`로 서버 업로드
- 업로드 후 서버가 음성 변환 처리

## 4. 지원 포맷

브라우저와 OS에 따라 녹음 포맷이 다를 수 있으므로 서버는 여러 포맷을 허용한다.

| 환경 | 우선 포맷 | 비고 |
| --- | --- | --- |
| Android Chrome | webm | MVP 기본 포맷 |
| iOS Safari | m4a 또는 mp4 | 브라우저 지원 상태 확인 필요 |
| 데스크톱 Chrome | webm | 테스트용 |

서버 허용 확장자는 다음으로 시작한다.

- `webm`
- `m4a`
- `mp4`
- `mp3`
- `wav`

## 5. 제한값

MVP 기본 제한은 다음과 같다.

| 항목 | 제한 |
| --- | --- |
| 최대 녹음 시간 | 3분 |
| 권장 녹음 시간 | 30초 ~ 1분 |
| 최대 파일 크기 | 20MB |
| 동시 업로드 | 1개 |
| 자동 분석 | 업로드 성공 후 자동 실행 |

녹음 시간이 길어지면 음성 변환 비용과 분석 토큰이 증가하므로 제한을 둔다.

## 6. 모바일 화면 요소

입력 화면의 음성 영역은 다음 요소를 포함한다.

- 녹음 시작 버튼
- 녹음 중지 버튼
- 녹음 취소 버튼
- 녹음 시간 표시
- 마이크 권한 상태
- 업로드 진행 상태
- 변환 중 상태
- 변환 텍스트 미리보기
- 다시 녹음 버튼
- 직접 텍스트 수정 영역

## 7. 상태값

프론트엔드 상태는 다음과 같이 관리한다.

- `permission_idle`: 권한 요청 전
- `permission_denied`: 마이크 권한 거부
- `ready`: 녹음 가능
- `recording`: 녹음 중
- `recorded`: 녹음 완료
- `uploading`: 업로드 중
- `uploaded`: 업로드 완료
- `transcribing`: 음성 변환 중
- `transcribed`: 변환 완료
- `failed`: 실패

## 8. 서버 업로드 API 초안

```http
POST /api/voice-inputs
Content-Type: multipart/form-data
```

요청 필드:

| 필드 | 설명 |
| --- | --- |
| `audio` | 녹음 파일 |
| `duration_seconds` | 녹음 길이 |
| `client_mime_type` | 브라우저 MIME 타입 |
| `client_timezone` | 클라이언트 시간대 |
| `submitted_by` | 입력자 ID |

응답 예시:

```json
{
  "raw_input_id": 1001,
  "processing_status": "transcribed",
  "transcribed_text": "김민수 대리한테 내일까지 견적서 수정본 확인하라고 업무 등록해줘.",
  "next_action": "analyze"
}
```

## 9. 서버 검증

서버는 업로드 파일을 다음 기준으로 검증한다.

- 파일 존재 여부
- 업로드 오류 여부
- MIME 타입 허용 여부
- 확장자 허용 여부
- 파일 크기 제한
- 녹음 시간 제한
- 저장 경로 생성 가능 여부

검증 실패 시 `raw_inputs`를 생성하지 않거나, 생성했다면 `processing_status`를 `failed`로 저장한다.

## 10. 저장 경로

음성 파일은 다음 구조로 저장한다.

```text
storage/audio/YYYY/MM/DD/{uuid}.{ext}
```

원본 파일명은 사용하지 않는다.

파일 경로는 `raw_inputs.audio_file_path`에 저장한다.

## 11. 음성 변환 처리

업로드가 끝나면 서버가 음성 텍스트 변환을 실행한다.

MVP에서는 업로드 요청 안에서 바로 변환해도 되지만, 파일이 크거나 응답 지연이 커지면 비동기 처리로 분리한다.

처리 결과:

- 성공: `raw_inputs.transcribed_text` 저장, `processing_status = transcribed`
- 실패: `processing_status = failed`, `error_message` 저장

## 12. 사용자 보정

음성 변환 결과는 사용자가 저장 전에 수정할 수 있어야 한다.

최종 AI 분석에는 사용자가 수정한 텍스트를 우선 사용한다.

원본 변환 텍스트와 사용자 수정 텍스트를 분리 저장할지 여부는 개발 단계에서 결정한다.

## 13. 실패 처리 문구

| 상황 | 문구 |
| --- | --- |
| 마이크 권한 거부 | 마이크 권한이 필요합니다. 브라우저 설정에서 마이크 권한을 허용해 주세요. |
| 녹음 미지원 | 이 브라우저에서는 직접 녹음을 지원하지 않습니다. 텍스트 입력을 사용해 주세요. |
| 녹음 시간 초과 | 녹음 시간이 너무 깁니다. 3분 이내로 다시 녹음해 주세요. |
| 업로드 실패 | 음성 파일을 업로드하지 못했습니다. 네트워크 상태를 확인해 주세요. |
| 변환 실패 | 음성을 텍스트로 변환하지 못했습니다. 직접 입력으로 전환해 주세요. |

## 14. 보안 원칙

- 음성 파일 업로드는 로그인 사용자만 허용한다.
- 서버는 파일명을 새로 생성한다.
- 업로드 파일은 public 경로에 직접 저장하지 않는다.
- 음성 파일 다운로드 URL은 기본 제공하지 않는다.
- 필요한 경우 관리자만 원본 음성에 접근할 수 있게 한다.

## 15. MVP 결정

MVP에서는 다음 정책으로 시작한다.

- 모바일 브라우저 직접 녹음을 기본 제공한다.
- Android Chrome은 우선 지원 대상으로 한다.
- iOS Safari는 테스트 후 제한 사항을 문서화한다.
- 최대 녹음 시간은 3분으로 제한한다.
- 음성 변환 후 사용자가 텍스트를 수정할 수 있게 한다.
