PLAUD 수준의 기능 확장: - 전사 편집: 인라인 편집 + 원본 보존 + 수정됨 표시(점선 밑줄) - 다중 문서 생성: 회의록/보고서/아이디어노트/커스텀 템플릿 - MD 에디터: 렌더링/편집 토글 (react-markdown + remark-gfm) - 상세 페이지 리디자인: 풀스크린 탭 전환 구조 - 내보내기: MD, PDF, TXT, DOCX 4종 (docx 패키지) - 커스텀 프롬프트 템플릿 저장/재사용 (electron-store) - SSOT: 마크다운 파싱 유틸 추출, 후처리에서 자동 문서 생성 제거 DB: meeting_documents 테이블 + edited_transcript 컬럼 IPC: 8+4 채널, 서비스 2개(MeetingModeService 확장 + MeetingDocTemplateService 신규) UI: 8개 신규 컴포넌트 (meeting/ 디렉토리), 12개 locale i18n
514 lines
17 KiB
Markdown
514 lines
17 KiB
Markdown
# Phase 14.5: 회의 모드 고도화 — 문서 생성/편집/내보내기
|
|
|
|
> PLAUD/Otter.ai 수준의 다중 문서 생성 + 전사 편집 + MD 에디터 + 다운로드 확장
|
|
> 기존 Phase 14 인프라(녹음+전사+메모+LLM) 위에 확장
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
### 1.1 사용자 플로우
|
|
|
|
```
|
|
[회의 종료 후 상세 페이지]
|
|
│
|
|
├── [Transcript 탭] ← 전사 원문 편집 + 원본/수정본 토글
|
|
│ ├── 세그먼트 클릭 → 인라인 편집 (점선 밑줄 + hover "수정됨")
|
|
│ ├── 원본 보기 토글 (rawTranscript ↔ editedTranscript)
|
|
│ └── [TXT 다운로드] 버튼
|
|
│
|
|
├── [+ 버튼] → 문서 생성 다이얼로그
|
|
│ ├── 템플릿 선택 (회의록 / 보고서 / 아이디어 노트 / 커스텀)
|
|
│ ├── 커스텀: 이름 + 프롬프트 입력 (저장/재사용 가능)
|
|
│ └── [생성] → LLM 호출 → 새 탭 추가
|
|
│
|
|
└── [문서 탭 (동적)] ← 회의록, 보고서 등
|
|
├── 미리보기 모드: react-markdown 렌더링
|
|
├── 편집 모드: 마크다운 원본 textarea
|
|
├── 토글 버튼 (미리보기 ↔ 편집)
|
|
├── debounce 자동 저장 (500ms)
|
|
└── [내보내기 ▼] 드롭다운 (MD / PDF / TXT / DOCX)
|
|
```
|
|
|
|
### 1.2 핵심 차별점
|
|
- **다중 문서**: 하나의 전사에서 여러 양식의 문서 생성 (PLAUD Multidimensional Summary)
|
|
- **전사 편집**: 녹음 중 + 종료 후 인라인 편집, 원본 보존, 수정 표시
|
|
- **커스텀 프롬프트**: 사용자 정의 AI 프롬프트 저장/재사용
|
|
- **4종 내보내기**: MD, PDF, TXT, DOCX
|
|
- **MD 에디터**: 렌더링/편집 토글
|
|
|
|
---
|
|
|
|
## 2. DB 스키마
|
|
|
|
### 2.1 `meeting_sessions` 테이블 확장
|
|
|
|
```sql
|
|
-- 마이그레이션: 전사 편집 원본 보존용 컬럼 추가
|
|
ALTER TABLE meeting_sessions ADD COLUMN edited_transcript TEXT;
|
|
```
|
|
|
|
### 2.2 `meeting_documents` 테이블 (신규)
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS meeting_documents (
|
|
id TEXT PRIMARY KEY,
|
|
session_id TEXT NOT NULL,
|
|
template_type TEXT NOT NULL, -- 'minutes' | 'report' | 'idea-note' | 'custom'
|
|
title TEXT NOT NULL,
|
|
content TEXT NOT NULL DEFAULT '',
|
|
prompt_used TEXT, -- 커스텀 프롬프트 기록용
|
|
llm_model TEXT,
|
|
llm_latency_ms INTEGER,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_meeting_documents_session_id ON meeting_documents(session_id);
|
|
```
|
|
|
|
### 2.3 drizzle-orm 스키마 (`src/main/db/schema.ts`)
|
|
|
|
```typescript
|
|
// meetingSessions에 추가
|
|
editedTranscript: text('edited_transcript'),
|
|
|
|
// 신규 테이블
|
|
export const meetingDocuments = sqliteTable(
|
|
'meeting_documents',
|
|
{
|
|
id: text('id').primaryKey(),
|
|
sessionId: text('session_id').notNull(),
|
|
templateType: text('template_type', {
|
|
enum: ['minutes', 'report', 'idea-note', 'custom'],
|
|
}).notNull(),
|
|
title: text('title').notNull(),
|
|
content: text('content').notNull().default(''),
|
|
promptUsed: text('prompt_used'),
|
|
llmModel: text('llm_model'),
|
|
llmLatencyMs: integer('llm_latency_ms'),
|
|
createdAt: integer('created_at').notNull(),
|
|
updatedAt: integer('updated_at').notNull(),
|
|
},
|
|
(table) => [
|
|
index('idx_meeting_documents_session_id').on(table.sessionId),
|
|
]
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 공유 타입 (`src/shared/types.ts`)
|
|
|
|
```typescript
|
|
// ============================================================
|
|
// Phase 14.5: Meeting Document Types
|
|
// ============================================================
|
|
|
|
export type MeetingDocTemplateType = 'minutes' | 'report' | 'idea-note' | 'custom'
|
|
|
|
export interface MeetingDocTemplate {
|
|
id: string
|
|
name: string
|
|
description: string
|
|
templateType: MeetingDocTemplateType
|
|
systemPrompt: string
|
|
isBuiltin: boolean
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface MeetingDocument {
|
|
id: string
|
|
sessionId: string
|
|
templateType: MeetingDocTemplateType
|
|
title: string
|
|
content: string
|
|
promptUsed: string | null
|
|
llmModel: string | null
|
|
llmLatencyMs: number | null
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface MeetingGenerateDocParams {
|
|
sessionId: string
|
|
templateId: string
|
|
customPrompt?: string
|
|
customTitle?: string
|
|
}
|
|
|
|
export interface MeetingGenerateDocResult {
|
|
document: MeetingDocument
|
|
}
|
|
|
|
export interface MeetingUpdateDocParams {
|
|
documentId: string
|
|
content: string
|
|
}
|
|
|
|
export interface MeetingDeleteDocParams {
|
|
documentId: string
|
|
}
|
|
|
|
export interface MeetingGetDocsParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingUpdateTranscriptParams {
|
|
sessionId: string
|
|
editedTranscript: string
|
|
}
|
|
|
|
export type MeetingExportFormat = 'md' | 'pdf' | 'txt' | 'docx'
|
|
|
|
export interface MeetingExportDocParams {
|
|
documentId: string
|
|
format: MeetingExportFormat
|
|
}
|
|
|
|
export interface MeetingExportTranscriptParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingDocGeneratingProgress {
|
|
sessionId: string
|
|
templateId: string
|
|
percent: number
|
|
}
|
|
|
|
export interface CreateMeetingDocTemplateParams {
|
|
name: string
|
|
description: string
|
|
systemPrompt: string
|
|
}
|
|
|
|
export interface UpdateMeetingDocTemplateParams {
|
|
id: string
|
|
name?: string
|
|
description?: string
|
|
systemPrompt?: string
|
|
}
|
|
|
|
export interface DeleteMeetingDocTemplateParams {
|
|
id: string
|
|
}
|
|
```
|
|
|
|
**MeetingSessionDetail 확장:**
|
|
```typescript
|
|
export interface MeetingSessionDetail extends MeetingSessionSummary {
|
|
rawTranscript: string | null
|
|
editedTranscript: string | null // 추가
|
|
minutesMarkdown: string | null
|
|
minutes: MeetingMinutes | null
|
|
memos: MeetingMemo[]
|
|
documents: MeetingDocument[] // 추가
|
|
sttModel: string | null
|
|
llmModel: string | null
|
|
errorMessage: string | null
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 에러 코드 (`src/shared/errors.ts`)
|
|
|
|
```typescript
|
|
// === Phase 14.5: Meeting Enhancement (886-892) ===
|
|
MeetingDocumentNotFound = 886,
|
|
MeetingDocGenerationFailed = 887,
|
|
MeetingDocExportFailed = 888,
|
|
MeetingTranscriptUpdateFailed = 889,
|
|
MeetingDocTemplateNotFound = 890,
|
|
MeetingDocTemplateBuiltinDelete = 891,
|
|
MeetingDocxExportFailed = 892,
|
|
```
|
|
|
|
---
|
|
|
|
## 5. IPC 채널 (`src/shared/ipc-channels.ts`)
|
|
|
|
```typescript
|
|
// MEETING_MODE 블록에 추가
|
|
UPDATE_TRANSCRIPT: 'meetingMode:updateTranscript',
|
|
GENERATE_DOCUMENT: 'meetingMode:generateDocument',
|
|
GET_DOCUMENTS: 'meetingMode:getDocuments',
|
|
UPDATE_DOCUMENT: 'meetingMode:updateDocument',
|
|
DELETE_DOCUMENT: 'meetingMode:deleteDocument',
|
|
EXPORT_DOCUMENT: 'meetingMode:exportDocument',
|
|
EXPORT_TRANSCRIPT: 'meetingMode:exportTranscript',
|
|
DOC_GENERATING_PROGRESS: 'meetingMode:docGeneratingProgress',
|
|
|
|
// 신규 그룹
|
|
MEETING_DOC_TEMPLATE: {
|
|
GET_ALL: 'meetingDocTemplate:getAll',
|
|
CREATE: 'meetingDocTemplate:create',
|
|
UPDATE: 'meetingDocTemplate:update',
|
|
DELETE: 'meetingDocTemplate:delete',
|
|
},
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 서비스 명세
|
|
|
|
### 6.1 MeetingDocTemplateService (신규)
|
|
|
|
**파일**: `src/main/services/MeetingDocTemplateService.ts`
|
|
**패턴**: electron-store 전용 인스턴스 (DictationTemplateService 패턴)
|
|
|
|
빌트인 3종:
|
|
|
|
```typescript
|
|
const BUILTIN_TEMPLATES: MeetingDocTemplate[] = [
|
|
{
|
|
id: 'builtin-minutes',
|
|
name: '회의록',
|
|
templateType: 'minutes',
|
|
systemPrompt: `전사록을 분석하여 구조화된 회의록을 작성하세요.
|
|
## 요약 (3-5줄)
|
|
## 핵심 결정사항 (- 항목)
|
|
## 할 일 목록 (- [ ] 담당자: 할일)
|
|
## 타임라인 (| 시간 | 내용 |)`,
|
|
isBuiltin: true,
|
|
},
|
|
{
|
|
id: 'builtin-report',
|
|
name: '보고서',
|
|
templateType: 'report',
|
|
systemPrompt: `전사록을 분석하여 제출용 보고서를 작성하세요.
|
|
## 개요 (배경, 목적)
|
|
## 핵심 내용 (주요 논의 사항)
|
|
## 결론 및 제안
|
|
## 첨부 참고사항`,
|
|
isBuiltin: true,
|
|
},
|
|
{
|
|
id: 'builtin-idea-note',
|
|
name: '아이디어 노트',
|
|
templateType: 'idea-note',
|
|
systemPrompt: `전사록에서 아이디어와 인사이트를 추출하세요.
|
|
## 핵심 아이디어 (번호 매기기)
|
|
## 각 아이디어의 장단점
|
|
## 우선순위 제안
|
|
## 다음 단계`,
|
|
isBuiltin: true,
|
|
},
|
|
]
|
|
```
|
|
|
|
메서드: `getAll()`, `getById()`, `create()`, `update()`, `delete()`
|
|
|
|
### 6.2 MeetingModeService 확장
|
|
|
|
**새 메서드:**
|
|
|
|
| 메서드 | 설명 |
|
|
|--------|------|
|
|
| `updateTranscript(sessionId, editedTranscript)` | 수정 전사 저장 |
|
|
| `generateDocument(params)` | 전사+템플릿→LLM→meeting_documents 저장 |
|
|
| `getDocuments(sessionId)` | 세션의 문서 목록 |
|
|
| `updateDocument(documentId, content)` | MD 편집 저장 |
|
|
| `deleteDocument(documentId)` | 문서 삭제 |
|
|
| `exportDocument(documentId, format)` | MD/PDF/TXT/DOCX 내보내기 |
|
|
| `exportTranscript(sessionId)` | 전사 TXT 다운로드 |
|
|
|
|
**후처리 변경:** `_runPostProcessing()`에서 자동 회의록 생성 제거. 전사 합산 + DB 저장(rawTranscript, status=completed)만 수행. 사용자가 [+]로 직접 문서 생성.
|
|
|
|
**_loadSessionDetail 확장:** editedTranscript + documents[] 포함
|
|
|
|
### 6.3 유틸 추출 (SSOT)
|
|
|
|
**`src/main/utils/meeting-markdown.ts`**:
|
|
- `parseMinutes(md)` — MeetingModeService._parseMinutes() 추출
|
|
- `buildExportMarkdown(session)` — _buildExportMarkdown() 추출
|
|
- `markdownToSimpleHtml(md)` — _markdownToSimpleHtml() 추출
|
|
|
|
**`src/main/utils/markdown-to-docx.ts`**:
|
|
- `markdownToDocx(md, title): Promise<Buffer>` — docx 패키지
|
|
|
|
---
|
|
|
|
## 7. Preload API (`src/preload/index.ts`)
|
|
|
|
```typescript
|
|
// meetingMode 확장
|
|
updateTranscript: (params) => invoke(ch.UPDATE_TRANSCRIPT, params),
|
|
generateDocument: (params) => invoke(ch.GENERATE_DOCUMENT, params),
|
|
getDocuments: (params) => invoke(ch.GET_DOCUMENTS, params),
|
|
updateDocument: (params) => invoke(ch.UPDATE_DOCUMENT, params),
|
|
deleteDocument: (params) => invoke(ch.DELETE_DOCUMENT, params),
|
|
exportDocument: (params) => invoke(ch.EXPORT_DOCUMENT, params),
|
|
exportTranscript: (params) => invoke(ch.EXPORT_TRANSCRIPT, params),
|
|
onDocGeneratingProgress: (cb) => on(ch.DOC_GENERATING_PROGRESS, cb),
|
|
|
|
// 신규 그룹
|
|
meetingDocTemplate: {
|
|
getAll: () => invoke(ch.GET_ALL),
|
|
create: (params) => invoke(ch.CREATE, params),
|
|
update: (params) => invoke(ch.UPDATE, params),
|
|
delete: (params) => invoke(ch.DELETE, params),
|
|
},
|
|
```
|
|
|
|
---
|
|
|
|
## 8. UI 컴포넌트
|
|
|
|
### 8.1 컴포넌트 디렉토리: `src/renderer/components/meeting/`
|
|
|
|
| 컴포넌트 | 설명 |
|
|
|----------|------|
|
|
| `EditableSegment.tsx` | 전사 세그먼트 인라인 편집. 클릭→TextField, 점선 밑줄, hover "수정됨" 툴팁 |
|
|
| `MarkdownRenderer.tsx` | react-markdown + remark-gfm 래퍼. d3roPalette 스타일 |
|
|
| `MarkdownEditor.tsx` | 미리보기/편집 토글. 편집 모드=textarea, debounce 자동저장(500ms) |
|
|
| `ExportMenu.tsx` | MD/PDF/TXT/DOCX 드롭다운 |
|
|
| `TranscriptTab.tsx` | 전사 편집 탭. 원본/수정본 토글, EditableSegment 목록, TXT 다운로드 |
|
|
| `DocumentTab.tsx` | 문서 탭. MarkdownEditor + ExportMenu + 삭제 |
|
|
| `AddDocumentDialog.tsx` | [+] 버튼 다이얼로그. 템플릿 선택(빌트인3+커스텀), 프롬프트 입력, 생성 |
|
|
| `MeetingDetailTabs.tsx` | 탭 바 + 콘텐츠 라우팅 컨테이너 |
|
|
|
|
### 8.2 상세 뷰 레이아웃
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────┐
|
|
│ [←] 프로젝트 킥오프 ✏️ [Export ▼] [🗑] │
|
|
│ 2026-04-06 14:30 ~ 15:12 · 42분 │
|
|
├──────────────────────────────────────────────────┤
|
|
│ [📝 Transcript] [회의록] [보고서] [+ 추가] │
|
|
├──────────────────────────────────────────────────┤
|
|
│ │
|
|
│ (선택된 탭의 풀스크린 콘텐츠) │
|
|
│ │
|
|
│ Transcript탭: EditableSegment 목록 │
|
|
│ 문서탭: MarkdownEditor (렌더링↔편집 토글) │
|
|
│ │
|
|
└──────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 8.3 녹음 뷰 세그먼트 편집
|
|
|
|
```
|
|
┌─ 실시간 전사 ScreenPanel ────────────────┐
|
|
│ [00:15] 안녕하세요 오늘 회의를... │ ← 클릭 시 편집 가능
|
|
│ ✏̣[̣0̣1̣:̣3̣0̣]̣ ̣예̣산̣ ̣관̣련̣인̣데̣요̣.̣.̣.̣ │ ← 수정됨: 점선 밑줄
|
|
│ [02:00] 다음 안건은... │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 9. i18n 키
|
|
|
|
### ko.json 추가
|
|
```json
|
|
"meeting.transcriptTab": "전사",
|
|
"meeting.addDocument": "문서 추가",
|
|
"meeting.selectTemplate": "템플릿 선택",
|
|
"meeting.generate": "생성",
|
|
"meeting.generating": "문서 생성 중...",
|
|
"meeting.editMode": "편집",
|
|
"meeting.previewMode": "미리보기",
|
|
"meeting.modified": "수정됨",
|
|
"meeting.originalText": "원본 보기",
|
|
"meeting.editedText": "수정본 보기",
|
|
"meeting.exportDocx": "DOCX 내보내기",
|
|
"meeting.exportTxt": "TXT 내보내기",
|
|
"meeting.exportFormat": "내보내기 형식",
|
|
"meeting.customPrompt": "커스텀 프롬프트",
|
|
"meeting.templateName": "템플릿 이름",
|
|
"meeting.templatePrompt": "AI 프롬프트",
|
|
"meeting.templateSave": "템플릿 저장",
|
|
"meeting.documentDeleted": "문서가 삭제되었습니다",
|
|
"meeting.autoSaved": "자동 저장됨",
|
|
"meeting.minutes": "회의록",
|
|
"meeting.report": "보고서",
|
|
"meeting.ideaNote": "아이디어 노트",
|
|
"meeting.custom": "커스텀"
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 구현 순서
|
|
|
|
### Step A: 기반 인프라 (타입 + DB + IPC 채널 + 에러코드)
|
|
1. `src/shared/types.ts` — 새 타입 추가 + MeetingSessionDetail 확장
|
|
2. `src/shared/ipc-channels.ts` — MEETING_MODE 확장 + MEETING_DOC_TEMPLATE 추가
|
|
3. `src/shared/errors.ts` — 886-892 추가
|
|
4. `src/main/db/schema.ts` — meetingDocuments + editedTranscript
|
|
5. `src/main/db/index.ts` — 마이그레이션 SQL
|
|
|
|
### Step B: npm 패키지 설치
|
|
6. `npm install react-markdown remark-gfm docx`
|
|
|
|
### Step C: 유틸 추출 (SSOT)
|
|
7. `src/main/utils/meeting-markdown.ts` — 파싱/내보내기 로직 추출
|
|
8. `src/main/utils/markdown-to-docx.ts` — DOCX 변환
|
|
|
|
### Step D: 서비스 계층
|
|
9. `src/main/services/MeetingDocTemplateService.ts` — 신규
|
|
10. `src/main/services/MeetingModeService.ts` — 확장 (7 메서드 + 후처리 변경 + _loadSessionDetail)
|
|
|
|
### Step E: IPC + Preload
|
|
11. `src/main/ipc/meeting-doc-template-handlers.ts` — 신규
|
|
12. `src/main/ipc/meeting-mode-handlers.ts` — 확장
|
|
13. `src/main/ipc/index.ts` — import 추가
|
|
14. `src/preload/index.ts` — API 확장
|
|
|
|
### Step F: UI 컴포넌트
|
|
15-22. `src/renderer/components/meeting/` — 8개 컴포넌트
|
|
|
|
### Step G: 페이지 통합
|
|
23. `src/renderer/pages/MeetingModePage.tsx` — 상세 뷰 리디자인 + 녹음 뷰 편집
|
|
|
|
### Step H: i18n
|
|
24. 12개 locale 키 추가
|
|
|
|
### Step I: 마무리
|
|
25. typecheck + build + test
|
|
26. bootstrap 초기화 단계 추가 (MeetingDocTemplateService)
|
|
|
|
---
|
|
|
|
## 11. TODO 항목 (향후 구현)
|
|
|
|
- [ ] AI 채팅: 회의록 레퍼런스 기반 Q&A (여러 레퍼런스 선택 + 대화)
|
|
- [ ] 웹 공유: 만료 링크 공유 (웹 서비스 연동 대비 설계)
|
|
- [ ] 마인드맵: AI 시각적 마인드맵 생성 (JPEG/SVG 내보내기)
|
|
- [ ] Auto Polish: AI 전사 다듬기 (필러 제거, 가독성 향상)
|
|
- [ ] 화자 구분: 스피커 라벨링 + 이름 지정
|
|
|
|
---
|
|
|
|
## 파일 목록
|
|
|
|
### 신규 (12개)
|
|
| 파일 | 설명 |
|
|
|------|------|
|
|
| `src/main/services/MeetingDocTemplateService.ts` | 문서 템플릿 CRUD |
|
|
| `src/main/ipc/meeting-doc-template-handlers.ts` | 템플릿 IPC |
|
|
| `src/main/utils/meeting-markdown.ts` | MD 파싱 유틸 |
|
|
| `src/main/utils/markdown-to-docx.ts` | DOCX 변환 |
|
|
| `src/renderer/components/meeting/MeetingDetailTabs.tsx` | 탭 컨테이너 |
|
|
| `src/renderer/components/meeting/TranscriptTab.tsx` | 전사 편집 탭 |
|
|
| `src/renderer/components/meeting/DocumentTab.tsx` | 문서 뷰/편집 탭 |
|
|
| `src/renderer/components/meeting/AddDocumentDialog.tsx` | 문서 생성 다이얼로그 |
|
|
| `src/renderer/components/meeting/MarkdownRenderer.tsx` | MD 렌더러 래퍼 |
|
|
| `src/renderer/components/meeting/MarkdownEditor.tsx` | 렌더링/편집 토글 |
|
|
| `src/renderer/components/meeting/EditableSegment.tsx` | 인라인 편집 세그먼트 |
|
|
| `src/renderer/components/meeting/ExportMenu.tsx` | 내보내기 드롭다운 |
|
|
|
|
### 수정 (10+12 locale)
|
|
| 파일 | 변경 |
|
|
|------|------|
|
|
| `src/shared/types.ts` | 새 타입 + MeetingSessionDetail 확장 |
|
|
| `src/shared/ipc-channels.ts` | 8+4 채널 |
|
|
| `src/shared/errors.ts` | 7개 에러 코드 |
|
|
| `src/main/db/schema.ts` | meetingDocuments + editedTranscript |
|
|
| `src/main/db/index.ts` | 마이그레이션 |
|
|
| `src/main/services/MeetingModeService.ts` | 7 메서드 + 후처리 변경 |
|
|
| `src/main/ipc/meeting-mode-handlers.ts` | 7 핸들러 |
|
|
| `src/main/ipc/index.ts` | import 추가 |
|
|
| `src/preload/index.ts` | API 확장 |
|
|
| `src/renderer/pages/MeetingModePage.tsx` | 상세 뷰 리디자인 |
|
|
| `src/renderer/i18n/*.json` | 12개 locale |
|