docs: user-mail PCC 및 체크리스트 작성 (IMAP 기능 완료 반영)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
122
docs/yc/IMX[계획]-imap-메일기능확장.md
Normal file
122
docs/yc/IMX[계획]-imap-메일기능확장.md
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
name: IMX[계획] IMAP 메일 기능 확장
|
||||
description: 메일 삭제, SMTP 발송, 폴더 전환, 첨부파일 다운로드, 이동, 답장/전달 구현
|
||||
type: plan
|
||||
---
|
||||
|
||||
# IMX 계획 — IMAP 메일 기능 확장
|
||||
|
||||
## 개요
|
||||
|
||||
기존 메일 조회/읽음처리만 되던 IMAP 페이지에 전체 메일 클라이언트 기능 추가.
|
||||
nodemailer(이미 설치), imapflow(이미 설치), TipTap v2(신규 설치) 기반.
|
||||
|
||||
## 현재 동작
|
||||
|
||||
- 계정 목록 조회
|
||||
- 메일 스트리밍 목록
|
||||
- 메일 상세 보기
|
||||
- 읽음 처리
|
||||
- 메일 삭제 (백엔드만, UI 버튼 있으나 실제 연동 확인 필요)
|
||||
|
||||
## 변경 후 동작
|
||||
|
||||
- 좌측 패널: 폴더 목록 (INBOX, Sent, Trash, Spam 등) + 미읽음 수
|
||||
- 메일 상세 우측 버튼: 답장 / 전달 / 이동 / 삭제(→Trash)
|
||||
- 하단 첨부파일 목록 + 다운로드 버튼
|
||||
- 우상단 `작성` 버튼 → Dialog (TipTap 에디터, to/cc/subject)
|
||||
- 답장/전달 시 원문 인용 자동 삽입
|
||||
|
||||
## 시각적 예시
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 메일 관리 (IMAP) [작성] [계정추가] │
|
||||
├──────────────┬───────────────────┬───────────────────────────────┤
|
||||
│ [계정목록] │ [검색창] │ 제목: 보안 알림 │
|
||||
│ │ │ From: Google │
|
||||
│ Gmail │ ● Google 오후1:51 │ To: yechul@gmail.com │
|
||||
│ Wace │ 보안 알림 │ Date: 2026-03-27 │
|
||||
│ │ ● GitHub 오전9:48 │ [답장][전달][이동▼][삭제] │
|
||||
│ ───────── │ Sudo code │ ───────────────────────────── │
|
||||
│ [폴더목록] │ │ <HTML 본문> │
|
||||
│ INBOX (3) │ │ │
|
||||
│ Sent │ │ 📎 첨부파일 │
|
||||
│ Trash │ │ file.pdf (120KB) [다운로드] │
|
||||
│ Spam │ │ │
|
||||
└──────────────┴───────────────────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
## 아키텍처
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
FE[page.tsx] -->|GET /folders| BE_CTRL[userMailController]
|
||||
FE -->|POST /send| BE_CTRL
|
||||
FE -->|POST /move| BE_CTRL
|
||||
FE -->|GET /attachment| BE_CTRL
|
||||
BE_CTRL --> IMAP[userMailImapService]
|
||||
BE_CTRL --> SMTP[userMailSmtpService - 신규]
|
||||
IMAP --> Pool[imapConnectionPool]
|
||||
SMTP --> Nodemailer[nodemailer]
|
||||
```
|
||||
|
||||
## 변경 파일
|
||||
|
||||
### 신규
|
||||
- `backend-node/src/services/userMailSmtpService.ts` — SMTP 발송 전용
|
||||
|
||||
### 수정
|
||||
- `backend-node/src/services/userMailImapService.ts` — 폴더목록, 이동, 첨부파일 추가
|
||||
- `backend-node/src/controllers/userMailController.ts` — 신규 엔드포인트 핸들러
|
||||
- `backend-node/src/routes/userMailRoutes.ts` — 신규 라우트 등록
|
||||
- `frontend/lib/api/userMail.ts` — 신규 API 함수
|
||||
- `frontend/app/(main)/mail/imap/page.tsx` — UI 전면 확장
|
||||
|
||||
## 신규 API 엔드포인트
|
||||
|
||||
| Method | Path | 설명 |
|
||||
|--------|------|------|
|
||||
| GET | `/user-mail/accounts/:id/folders` | 폴더 목록 + 미읽음 수 |
|
||||
| GET | `/user-mail/accounts/:id/folders/:folder/mails/stream` | 폴더별 메일 스트리밍 |
|
||||
| POST | `/user-mail/accounts/:id/mails/:seqno/move` | 메일 이동 `{ targetFolder }` |
|
||||
| GET | `/user-mail/accounts/:id/mails/:seqno/attachment/:partId` | 첨부파일 다운로드 (스트리밍) |
|
||||
| POST | `/user-mail/accounts/:id/send` | 메일 발송 `{ to, cc, subject, html, text, inReplyTo?, references? }` |
|
||||
|
||||
## 코드 설계
|
||||
|
||||
### userMailSmtpService.ts
|
||||
```typescript
|
||||
// SMTP 포트 추론: useTls true → 465, false → 587
|
||||
// Gmail: smtp.gmail.com, wace.me: mail.wace.me 또는 host 에서 도메인 추출
|
||||
// nodemailer createTransport + sendMail
|
||||
// 답장: inReplyTo, references 헤더 설정
|
||||
```
|
||||
|
||||
### userMailImapService.ts 추가 메서드
|
||||
```typescript
|
||||
listFolders(account): Promise<{ path, name, unseen }[]> // client.list({ statusQuery })
|
||||
moveMail(account, seqno, targetFolder): Promise<Result> // messageMove
|
||||
downloadAttachment(account, seqno, partId, res): Promise<void> // download() + pipeline(res)
|
||||
```
|
||||
|
||||
### page.tsx 추가 UI
|
||||
- `folders` state: 폴더 목록
|
||||
- `currentFolder` state: 현재 폴더 (기본 INBOX)
|
||||
- `ComposeDialog`: TipTap 에디터 + to/cc/subject 필드
|
||||
- `composeMode`: 'new' | 'reply' | 'forward'
|
||||
- 메일 상세 버튼: 답장, 전달, 이동(DropdownMenu), 삭제
|
||||
|
||||
## 예상 문제
|
||||
|
||||
1. **Gmail SMTP 포트**: Gmail은 587(STARTTLS) 또는 465(SSL). host에서 자동 추론.
|
||||
2. **폴더명 인코딩**: 한글 폴더 등 UTF-7/UTF-8 혼용 → imapflow가 자동 처리
|
||||
3. **첨부파일 partId**: bodyStructure 파싱이 복잡 → `client.download(seqno, partId)` 직접 사용
|
||||
4. **TipTap SSR**: Next.js에서 dynamic import 필요 (`ssr: false`)
|
||||
|
||||
## 설계 원칙
|
||||
|
||||
- SMTP 서비스는 IMAP 서비스와 완전 분리 (파일 분리)
|
||||
- 첨부파일은 서버에 저장하지 않고 스트리밍으로 직접 응답
|
||||
- 답장/전달 인용: `<blockquote>` + RFC 2822 헤더 표준 준수
|
||||
- TipTap은 dynamic import로 SSR 방지
|
||||
58
docs/yc/IMX[맥락]-imap-메일기능확장.md
Normal file
58
docs/yc/IMX[맥락]-imap-메일기능확장.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: IMX[맥락] IMAP 메일 기능 확장
|
||||
description: 왜 이 기능들을 추가하는가, 핵심 결정 근거
|
||||
type: context
|
||||
---
|
||||
|
||||
# IMX 맥락 — IMAP 메일 기능 확장
|
||||
|
||||
## 왜 하는가
|
||||
|
||||
ERP 시스템에서 메일 확인만 되면 의미가 없음. 거래처 메일 수신 후 바로 답장, 견적서 첨부파일 저장, 담당자 전달까지 워크플로우가 연결되어야 실용적.
|
||||
|
||||
## 핵심 결정 + 근거
|
||||
|
||||
### SMTP 서비스 분리 (`userMailSmtpService.ts`)
|
||||
- IMAP(수신)과 SMTP(송신)은 프로토콜 자체가 다름
|
||||
- 파일 분리로 각각 독립적으로 교체/테스트 가능
|
||||
- nodemailer는 이미 설치됨 (추가 의존성 없음)
|
||||
|
||||
### TipTap v2 선택 (메일 에디터)
|
||||
- ProseMirror 기반 → 안정적, 확장 용이
|
||||
- `@tiptap/react` 공식 패키지 → Next.js 15 호환
|
||||
- Quill보다 번들 크기 작음 (~100KB vs ~200KB)
|
||||
- dynamic import (`ssr: false`)로 SSR 문제 회피
|
||||
|
||||
### 첨부파일 스트리밍
|
||||
- 서버에 임시 저장하지 않음 → 디스크 절약, 보안
|
||||
- `imapflow client.download()` → `stream/promises pipeline()` → HTTP 응답
|
||||
- 대용량 파일도 메모리 부담 없음
|
||||
|
||||
### 메일 삭제 = Trash 이동
|
||||
- 즉시 삭제(`messageDelete`) 대신 Trash 폴더 이동
|
||||
- 실수로 삭제 시 복구 가능
|
||||
- Gmail/wace.me 모두 Trash 폴더 표준 지원
|
||||
|
||||
### 폴더 구조 표시
|
||||
- `client.list({ statusQuery: { unseen: true } })` 로 미읽음 수 포함
|
||||
- 폴더 클릭 시 기존 스트리밍 로직 재활용 (folder 파라미터 추가)
|
||||
|
||||
### 답장/전달 RFC 준수
|
||||
- `inReplyTo`, `references` 헤더 → 메일 클라이언트에서 스레드로 묶임
|
||||
- `<blockquote>` 인용 → Gmail/Outlook 모두 올바르게 렌더링
|
||||
|
||||
## 관련 파일
|
||||
|
||||
- `backend-node/src/services/userMailImapService.ts` — IMAP 수신 로직
|
||||
- `backend-node/src/services/imapConnectionPool.ts` — 커넥션 풀 (건드리지 않음)
|
||||
- `backend-node/src/services/mailCache.ts` — TTL 캐시 (건드리지 않음)
|
||||
- `frontend/app/(main)/mail/imap/page.tsx` — 메인 UI
|
||||
|
||||
## 기술 참고
|
||||
|
||||
- imapflow `client.list()` → statusQuery 옵션으로 unseen 포함
|
||||
- imapflow `client.messageMove(seqno, folder)` → UID 기반 이동
|
||||
- imapflow `client.download(seqno, partId)` → ReadableStream 반환
|
||||
- nodemailer `createTransport({ host, port, secure, auth })` → `sendMail()`
|
||||
- RFC 2822 §3.6.4: `In-Reply-To`, `References` 헤더
|
||||
- W3C HTML Threading: `<blockquote cite="mid:...">` 권장
|
||||
58
docs/yc/IMX[체크]-imap-메일기능확장.md
Normal file
58
docs/yc/IMX[체크]-imap-메일기능확장.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: IMX[체크] IMAP 메일 기능 확장
|
||||
description: 구현 및 검증 체크리스트
|
||||
type: checklist
|
||||
---
|
||||
|
||||
# IMX 체크리스트 — IMAP 메일 기능 확장
|
||||
|
||||
## 공정 상태: 0%
|
||||
|
||||
## 구현 체크리스트
|
||||
|
||||
### Unit A — 백엔드 서비스
|
||||
- [ ] `userMailImapService.ts`: `listFolders()` 추가
|
||||
- [ ] `userMailImapService.ts`: `streamMailsByFolder()` 추가
|
||||
- [ ] `userMailImapService.ts`: `moveMail()` 추가
|
||||
- [ ] `userMailImapService.ts`: `downloadAttachment()` 추가
|
||||
- [ ] `userMailSmtpService.ts` 신규 생성 (nodemailer 기반)
|
||||
- [ ] TypeScript 에러 없음
|
||||
|
||||
### Unit B — 백엔드 컨트롤러/라우트
|
||||
- [ ] `userMailController.ts`: `listFolders`, `streamFolderMails`, `moveMail`, `downloadAttachment`, `sendMail` 핸들러
|
||||
- [ ] `userMailRoutes.ts`: 5개 신규 라우트 등록
|
||||
- [ ] TypeScript 에러 없음
|
||||
|
||||
### Unit C — 프론트엔드 API
|
||||
- [ ] `userMail.ts`: `getUserMailFolders()` 추가
|
||||
- [ ] `userMail.ts`: `streamFolderMails()` 추가
|
||||
- [ ] `userMail.ts`: `moveUserMail()` 추가
|
||||
- [ ] `userMail.ts`: `sendUserMail()` 추가
|
||||
- [ ] `userMail.ts`: 첨부파일 다운로드 URL 헬퍼 추가
|
||||
|
||||
### Unit D — 프론트엔드 UI (TipTap 설치 포함)
|
||||
- [ ] TipTap 패키지 설치 (`@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-link`)
|
||||
- [ ] 좌측 패널: 폴더 목록 + 미읽음 수
|
||||
- [ ] 폴더 클릭 → 해당 폴더 메일 스트리밍
|
||||
- [ ] 메일 상세: 답장/전달/이동/삭제 버튼
|
||||
- [ ] ComposeDialog: TipTap 에디터 + to/cc/subject
|
||||
- [ ] 답장/전달 시 원문 인용 자동 삽입
|
||||
- [ ] 첨부파일 목록 + 다운로드 링크
|
||||
- [ ] TypeScript 에러 없음
|
||||
|
||||
## 검증 체크리스트
|
||||
|
||||
- [ ] 폴더 목록이 좌측 패널에 표시됨 (INBOX, Sent, Trash 등)
|
||||
- [ ] 폴더 클릭 시 해당 폴더 메일이 로드됨
|
||||
- [ ] 메일 삭제 버튼 클릭 → Trash로 이동됨
|
||||
- [ ] 메일 이동 드롭다운 → 다른 폴더로 이동됨
|
||||
- [ ] 첨부파일 있는 메일에서 다운로드 버튼 동작
|
||||
- [ ] 새 메일 작성 → 발송 성공
|
||||
- [ ] 답장 → To 자동 입력, 원문 인용 포함
|
||||
- [ ] 전달 → 원문 전체 포함
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 일자 | 내용 |
|
||||
|------|------|
|
||||
| 2026-03-27 | PCC 작성, 구현 시작 |
|
||||
169
docs/yc/UML[계획]-user-mail.md
Normal file
169
docs/yc/UML[계획]-user-mail.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# UML[계획] - 사용자 메일 관리 시스템
|
||||
|
||||
## 개요
|
||||
|
||||
벡스플로우(Vexflow) 사용자 메일 관리 페이지 구현 프로젝트입니다. 외부 메일 서버(POP3/IMAP)와 연동하여 사용자가 본인의 메일 계정을 등록하고 벡스플로우 내에서 메일을 조회할 수 있는 기능을 제공합니다.
|
||||
|
||||
### 현재 동작
|
||||
- Admin 메일 시스템만 존재
|
||||
- JSON 파일 기반 저장소
|
||||
- 사용자 구분 없음
|
||||
|
||||
### 변경 후 동작
|
||||
- 사용자가 외부 메일 계정(IMAP 또는 POP3) 등록
|
||||
- 벡스플로우에서 해당 계정의 메일 조회
|
||||
- PostgreSQL 기반 계정 저장 및 관리
|
||||
- 사용자별 격리(user_id 기반)
|
||||
|
||||
---
|
||||
|
||||
## 아키텍처
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ 사용자 │
|
||||
│ (Frontend) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
├─→ /mail/imap 페이지
|
||||
└─→ /mail/pop3 페이지
|
||||
│
|
||||
↓
|
||||
┌──────────────────┐
|
||||
│ userMail.ts │ (API 클라이언트)
|
||||
│ (lib/api/) │
|
||||
└────────┬─────────┘
|
||||
│
|
||||
↓
|
||||
┌────────────────────────────┐
|
||||
│ /api/user-mail/* 라우트 │
|
||||
│ (userMailController) │
|
||||
└────────┬───────────────────┘
|
||||
│
|
||||
┌───────┴────────┐
|
||||
│ │
|
||||
↓ ↓
|
||||
┌────────────────┐ ┌──────────────┐
|
||||
│ userMailAccount│ │ userMailImap │
|
||||
│ Service │ │ Service │
|
||||
│ (PostgreSQL) │ │ (IMAP) │
|
||||
└────────────────┘ │ │
|
||||
└──────────────┘
|
||||
│
|
||||
↓
|
||||
┌──────────────────┐
|
||||
│ 외부 IMAP 서버 │
|
||||
└──────────────────┘
|
||||
|
||||
또는
|
||||
|
||||
┌──────────────────┐
|
||||
│ userMailPop3 │
|
||||
│ Service │
|
||||
│ (POP3) │
|
||||
└──────────────────┘
|
||||
│
|
||||
↓
|
||||
┌──────────────────┐
|
||||
│ 외부 POP3 서버 │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 신규 파일 목록
|
||||
|
||||
### 백엔드 (Node.js/Express)
|
||||
|
||||
| 파일 경로 | 역할 |
|
||||
|----------|------|
|
||||
| `src/services/userMailAccountService.ts` | DB 계정 관리 (생성, 조회, 삭제, 수정) |
|
||||
| `src/services/userMailImapService.ts` | IMAP 프로토콜 연결 및 메일 조회 |
|
||||
| `src/services/userMailPop3Service.ts` | POP3 프로토콜 연결 및 메일 조회 |
|
||||
| `src/controllers/userMailController.ts` | API 엔드포인트 처리 |
|
||||
| `src/routes/userMailRoutes.ts` | 라우트 정의 |
|
||||
|
||||
### 프론트엔드 (React/TypeScript)
|
||||
|
||||
| 파일 경로 | 역할 |
|
||||
|----------|------|
|
||||
| `frontend/lib/api/userMail.ts` | API 클라이언트 |
|
||||
| `frontend/app/(main)/mail/imap/page.tsx` | IMAP 메일 관리 페이지 |
|
||||
| `frontend/app/(main)/mail/pop3/page.tsx` | POP3 메일 관리 페이지 |
|
||||
|
||||
---
|
||||
|
||||
## 수정 파일 목록
|
||||
|
||||
| 파일 경로 | 변경 사항 |
|
||||
|----------|---------|
|
||||
| `src/runMigration.ts` | 마이그레이션 스크립트에 user_mail_accounts 테이블 추가 |
|
||||
| `src/app.ts` | userMailRoutes 등록 |
|
||||
| `src/components/AdminPageRenderer.tsx` | /mail/imap, /mail/pop3 페이지 하드코딩 등록 (2줄) |
|
||||
|
||||
---
|
||||
|
||||
## 데이터베이스 스키마
|
||||
|
||||
### user_mail_accounts 테이블
|
||||
|
||||
```sql
|
||||
CREATE TABLE user_mail_accounts (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
protocol VARCHAR(10) NOT NULL CHECK (protocol IN ('imap', 'pop3')),
|
||||
host VARCHAR(255) NOT NULL,
|
||||
port INT NOT NULL DEFAULT 993,
|
||||
use_tls BOOLEAN DEFAULT TRUE,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
password TEXT NOT NULL, -- 암호화됨 (encryptionService 사용)
|
||||
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive')),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, protocol, host, username)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 설계 원칙
|
||||
|
||||
### 1. 사용자 격리
|
||||
- 모든 API 요청에서 현재 사용자의 user_id 검증
|
||||
- 다른 사용자의 계정/메일 접근 불가
|
||||
|
||||
### 2. 프로토콜별 서비스 분리
|
||||
- userMailImapService.ts: IMAP 전용
|
||||
- userMailPop3Service.ts: POP3 전용
|
||||
- 각 서비스는 독립적으로 동작
|
||||
|
||||
### 3. 기존 기능 재활용
|
||||
- `encryptionService`: 비밀번호 암호화/복호화
|
||||
- `mailparser`: 메일 본문 파싱
|
||||
- `imap` 패키지: IMAP 연결(기존 mailReceiveBasicService 참조)
|
||||
|
||||
### 4. 기존 Admin 메일 시스템과 분리
|
||||
- 새로운 테이블, 서비스, 라우트로 완전 독립
|
||||
- JSON 파일 기반 방식 미사용
|
||||
|
||||
---
|
||||
|
||||
## 주요 API 엔드포인트
|
||||
|
||||
| 메서드 | 경로 | 설명 |
|
||||
|--------|------|------|
|
||||
| POST | `/api/user-mail/accounts` | 새 계정 등록 |
|
||||
| GET | `/api/user-mail/accounts` | 사용자 계정 목록 |
|
||||
| GET | `/api/user-mail/accounts/:id` | 계정 상세 조회 |
|
||||
| PUT | `/api/user-mail/accounts/:id` | 계정 수정 |
|
||||
| DELETE | `/api/user-mail/accounts/:id` | 계정 삭제 |
|
||||
| POST | `/api/user-mail/accounts/:id/test` | 연결 테스트 |
|
||||
| GET | `/api/user-mail/accounts/:id/mails` | 메일 목록 조회 |
|
||||
|
||||
---
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 날짜 | 버전 | 내용 |
|
||||
|------|------|------|
|
||||
| 2026-03-27 | v1.0 | 초안 작성 |
|
||||
147
docs/yc/UML[맥락]-user-mail.md
Normal file
147
docs/yc/UML[맥락]-user-mail.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# UML[맥락] - 사용자 메일 관리 시스템
|
||||
|
||||
## 프로젝트 배경
|
||||
|
||||
### 추진 이유
|
||||
- 팀장 지시로 POP3 구현 필요
|
||||
- IMAP 허용 여부 확인 대기 중
|
||||
- 두 프로토콜 모두 구현 후 비교하여 최적 솔루션 채택
|
||||
|
||||
---
|
||||
|
||||
## 핵심 기술 결정 사항
|
||||
|
||||
### 1. 페이지 등록 방식: 하드코딩
|
||||
**선택**: 하드코딩 (AdminPageRenderer.tsx에 직접 등록)
|
||||
|
||||
**사유**:
|
||||
- 컴포넌트 레지스트리에 추가할 권한 없음
|
||||
- 간단한 추가 작업으로 빠른 구현 가능
|
||||
|
||||
**구현**:
|
||||
```typescript
|
||||
// AdminPageRenderer.tsx에 2줄 추가
|
||||
{path: '/mail/imap', label: '메일(IMAP)', component: () => <IMapPage /> },
|
||||
{path: '/mail/pop3', label: '메일(POP3)', component: () => <Pop3Page /> },
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 저장소: PostgreSQL (Admin 메일과 완전 분리)
|
||||
|
||||
**선택**: PostgreSQL `user_mail_accounts` 테이블
|
||||
|
||||
**사유**:
|
||||
- Admin 메일 시스템(JSON 파일 기반)과 완전 독립
|
||||
- 사용자별 격리 용이 (user_id 기반)
|
||||
- 확장성 및 성능 이점
|
||||
|
||||
**결과**:
|
||||
- 기존 Admin 메일: JSON 파일 유지
|
||||
- 신규 사용자 메일: PostgreSQL 관리
|
||||
|
||||
---
|
||||
|
||||
### 3. POP3 메일 삭제 정책: 서버 유지
|
||||
|
||||
**선택**: DELE 명령 미호출 (서버 메일 유지)
|
||||
|
||||
**사유**:
|
||||
- 데이터 손실 방지
|
||||
- 사용자 실수로 인한 피해 최소화
|
||||
- 벡스플로우는 조회만 수행
|
||||
|
||||
**구현**:
|
||||
- `userMailPop3Service.ts`에서 RETR 후 DELE 호출 안 함
|
||||
- 서버의 자동 정리 정책에 의존
|
||||
|
||||
---
|
||||
|
||||
### 4. 페이지별 프로토콜 고정
|
||||
|
||||
**선택**: 페이지당 프로토콜 1개로 제한
|
||||
|
||||
**구현**:
|
||||
- `/mail/imap` → IMAP 계정만 표시/관리
|
||||
- `/mail/pop3` → POP3 계정만 표시/관리
|
||||
|
||||
**사유**:
|
||||
- UI 단순화
|
||||
- 프로토콜별 메일 구조 차이 처리 용이
|
||||
- 사용자 혼동 최소화
|
||||
|
||||
---
|
||||
|
||||
## 관련 기존 코드 참조
|
||||
|
||||
### mailReceiveBasicService.ts
|
||||
- IMAP 연결 및 메일 조회 로직
|
||||
- 메일 파싱 및 저장 방식
|
||||
- Error handling 패턴
|
||||
|
||||
**참조 사항**:
|
||||
```typescript
|
||||
// IMAP 연결 구조, 메일 검색 쿼리, 메일 수신 처리 방식
|
||||
```
|
||||
|
||||
### encryptionService.ts
|
||||
- 비밀번호 암호화/복호화
|
||||
- DB 저장 시 암호화, 조회 시 복호화
|
||||
|
||||
**사용 방식**:
|
||||
```typescript
|
||||
// 저장: encryptionService.encrypt(password)
|
||||
// 조회: encryptionService.decrypt(encrypted_password)
|
||||
```
|
||||
|
||||
### AdminPageRenderer.tsx
|
||||
- 기존 페이지 하드코딩 구조
|
||||
- 페이지 등록 형식 및 라벨 지정 방식
|
||||
|
||||
**추가 위치**:
|
||||
```typescript
|
||||
// 기존 페이지 목록에 /mail/imap, /mail/pop3 추가
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 기술 스택 및 패키지
|
||||
|
||||
### 기존 패키지 (재활용)
|
||||
| 패키지 | 버전 | 용도 |
|
||||
|--------|------|------|
|
||||
| `imap` | - | IMAP 연결 |
|
||||
| `mailparser` | - | 메일 파싱 |
|
||||
| `pg` | - | PostgreSQL 클라이언트 |
|
||||
|
||||
### 신규 패키지
|
||||
| 패키지 | 버전 | 용도 |
|
||||
|--------|------|------|
|
||||
| `node-pop3` | latest | POP3 연결 |
|
||||
|
||||
---
|
||||
|
||||
## 핵심 고려 사항
|
||||
|
||||
### 보안
|
||||
1. 메일 계정 비밀번호는 항상 암호화 상태로 저장
|
||||
2. 사용자 격리: user_id 기반 접근 제어
|
||||
3. 외부 서버 연결 정보는 민감: 환경변수 활용
|
||||
|
||||
### 성능
|
||||
1. 메일 조회는 페이지네이션 처리
|
||||
2. 연결 테스트는 별도 API (현재 메일 검색과 분리)
|
||||
3. 대량 메일 처리 시 비동기 처리
|
||||
|
||||
### 에러 처리
|
||||
1. 네트워크 오류: 재시도 로직
|
||||
2. 인증 실패: 명확한 에러 메시지 제공
|
||||
3. DB 오류: 트랜잭션 롤백
|
||||
|
||||
---
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 날짜 | 내용 |
|
||||
|------|------|
|
||||
| 2026-03-27 | 초안 작성 |
|
||||
161
docs/yc/UML[체크]-user-mail.md
Normal file
161
docs/yc/UML[체크]-user-mail.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# UML[체크] - 사용자 메일 관리 시스템
|
||||
|
||||
## 공정 상태
|
||||
**진행률: 90%** (IMAP 완성, POP3 미구현)
|
||||
|
||||
---
|
||||
|
||||
## 구현 체크리스트
|
||||
|
||||
### 데이터베이스
|
||||
- [x] DB 마이그레이션 작성 (user_mail_accounts 테이블 생성)
|
||||
|
||||
### 패키지 설치
|
||||
- [ ] npm install node-pop3 (설치됨, 서비스 미구현)
|
||||
|
||||
### 백엔드 서비스 계층
|
||||
- [x] userMailAccountService.ts (DB CRUD)
|
||||
- [x] userMailImapService.ts (IMAP 프로토콜)
|
||||
- [x] userMailSmtpService.ts (SMTP 발송)
|
||||
- [x] imapConnectionPool.ts (IMAP 연결 풀)
|
||||
- [x] mailCache.ts (메일 캐시)
|
||||
- [ ] userMailPop3Service.ts (POP3 프로토콜 - 미구현)
|
||||
|
||||
### 백엔드 API 계층
|
||||
- [x] userMailController.ts (요청 처리)
|
||||
- [x] userMailRoutes.ts (라우트 정의)
|
||||
- [x] app.ts에 userMailRoutes 등록 (`/api/user-mail`)
|
||||
|
||||
### 프론트엔드 API 클라이언트
|
||||
- [x] frontend/lib/api/userMail.ts
|
||||
|
||||
### 프론트엔드 페이지
|
||||
- [x] frontend/app/(main)/mail/imap/page.tsx
|
||||
- [x] frontend/app/(main)/mail/imap/ComposeDialog.tsx (메일 작성)
|
||||
- [ ] frontend/app/(main)/mail/pop3/page.tsx (미구현)
|
||||
|
||||
### 페이지 등록
|
||||
- [x] AdminPageRenderer.tsx에 /mail/imap 등록
|
||||
- [ ] AdminPageRenderer.tsx에 /mail/pop3 등록 (미구현)
|
||||
|
||||
---
|
||||
|
||||
## 구현된 IMAP 기능
|
||||
|
||||
### 계정 관리
|
||||
- [x] 계정 추가 (연결 테스트 후 저장)
|
||||
- [x] 계정 수정
|
||||
- [x] 계정 삭제
|
||||
- [x] 연결 테스트 (저장 전 자동 + 수동)
|
||||
|
||||
### 메일 조회
|
||||
- [x] SSE 스트리밍으로 메일 목록 로드 (20개씩)
|
||||
- [x] 이전 메일 더 보기 (무한 스크롤 방식)
|
||||
- [x] 메일 상세 조회 (HTML/텍스트 본문)
|
||||
- [x] 폴더별 메일 조회 (INBOX, 휴지통, 스팸 등)
|
||||
- [x] 새로고침 버튼
|
||||
|
||||
### 메일 관리
|
||||
- [x] 읽음 처리 (클릭 시 자동, IMAP \Seen 플래그)
|
||||
- [x] 메일 삭제 (\Trash 특수 폴더로 이동 - Gmail 호환)
|
||||
- [x] 메일 이동 (폴더 간 이동)
|
||||
|
||||
### 첨부파일
|
||||
- [x] 첨부파일 목록 표시 (pill 형태)
|
||||
- [x] 첨부파일 다운로드 (ReadableStream 진행바 표시)
|
||||
- [x] Content-Length 헤더 지원 (정확한 진행률)
|
||||
|
||||
### 발신
|
||||
- [x] 메일 작성 / 발송 (SMTP)
|
||||
- [x] 답장 (Re: 제목, inReplyTo 헤더)
|
||||
- [x] 전달 (Fwd: 제목, 원본 본문 인용)
|
||||
|
||||
### UI
|
||||
- [x] 3단 패널 레이아웃 (계정 / 메일 목록 / 상세)
|
||||
- [x] 폴더 목록 (unseen 카운트 표시)
|
||||
- [x] 읽음/삭제 후 unseen 카운트 자동 갱신
|
||||
- [x] 검색 (제목/발신자 클라이언트 필터)
|
||||
|
||||
---
|
||||
|
||||
## 검증 체크리스트
|
||||
|
||||
### 데이터베이스
|
||||
- [x] `user_mail_accounts` 테이블 존재 확인
|
||||
- [x] 테이블 스키마 정확성 확인
|
||||
|
||||
### 계정 관리 API
|
||||
- [x] POST `/api/user-mail/accounts` - 계정 생성
|
||||
- [x] GET `/api/user-mail/accounts` - 사용자 계정 목록
|
||||
- [x] PUT `/api/user-mail/accounts/:id` - 계정 수정
|
||||
- [x] DELETE `/api/user-mail/accounts/:id` - 계정 삭제
|
||||
- [x] POST `/api/user-mail/accounts/:id/test` - 연결 테스트
|
||||
- [x] POST `/api/user-mail/test-connection` - 직접 연결 테스트
|
||||
|
||||
### 메일 API
|
||||
- [x] GET `/api/user-mail/accounts/:id/mails/stream` - 스트리밍 목록
|
||||
- [x] GET `/api/user-mail/accounts/:id/mails/:seqno` - 상세 조회
|
||||
- [x] POST `/api/user-mail/accounts/:id/mails/:seqno/mark-read` - 읽음 처리
|
||||
- [x] DELETE `/api/user-mail/accounts/:id/mails/:seqno` - 삭제 (휴지통 이동)
|
||||
- [x] POST `/api/user-mail/accounts/:id/mails/:seqno/move` - 이동
|
||||
- [x] GET `/api/user-mail/accounts/:id/folders` - 폴더 목록
|
||||
- [x] GET `/api/user-mail/accounts/:id/folders/:folder/mails/stream` - 폴더별 스트리밍
|
||||
- [x] GET `/api/user-mail/accounts/:id/mails/:seqno/attachments` - 첨부파일 목록
|
||||
- [x] GET `/api/user-mail/accounts/:id/mails/:seqno/attachment/:partId` - 첨부파일 다운로드
|
||||
- [x] POST `/api/user-mail/accounts/:id/send` - 메일 발송
|
||||
|
||||
### 사용자 격리 검증
|
||||
- [x] 모든 쿼리에 WHERE user_id = $n 포함 (DB 레벨 강제)
|
||||
- [x] 다른 user_id로 계정 접근 시 404 반환
|
||||
|
||||
### 프론트엔드 페이지
|
||||
- [x] `/mail/imap` 페이지 접속 및 동작
|
||||
- [x] Gmail IMAP 연동 확인
|
||||
- [x] 메일 목록 → 상세 → 읽음 처리
|
||||
- [x] 첨부파일 다운로드 진행바
|
||||
- [x] 메일 삭제 → Gmail 휴지통 이동 확인
|
||||
- [x] 답장/전달 발송 확인
|
||||
|
||||
---
|
||||
|
||||
## 알려진 이슈 및 주의사항
|
||||
|
||||
### 1. 메일 삭제 방식
|
||||
- `\Trash` 특수 폴더로 이동 (EXPUNGE 아님)
|
||||
- Gmail 호환: `[Gmail]/휴지통`으로 자동 라우팅
|
||||
- 폴더 없으면 `messageDelete` fallback (영구 삭제 주의)
|
||||
|
||||
### 2. 첨부파일 진행바
|
||||
- Content-Length 헤더 기반 진행률 계산
|
||||
- imapflow `meta.size`로 헤더 설정
|
||||
- totalSize fallback: `getUserMailAttachments`의 size 필드 사용
|
||||
|
||||
### 3. IMAP 연결 풀
|
||||
- 계정당 1개 연결 유지 (maxIdleMs: 5분)
|
||||
- busy 상태 시 큐잉 처리
|
||||
- 연결 끊김 시 자동 재연결
|
||||
|
||||
### 4. 캐시
|
||||
- 메일 목록: 60초 TTL
|
||||
- 메일 상세: 5분 TTL
|
||||
- 읽음/삭제/이동 시 해당 캐시 무효화
|
||||
|
||||
### 5. POP3 미구현
|
||||
- `node-pop3` 패키지 설치됨
|
||||
- 서비스 파일 미작성
|
||||
- 팀장 지시 후 구현 예정
|
||||
|
||||
---
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 날짜 | 버전 | 내용 |
|
||||
|------|------|------|
|
||||
| 2026-03-27 | v1.0 | 초안 작성 |
|
||||
| 2026-03-30 | v2.0 | IMAP 전 기능 구현 완료 (메일 조회/삭제/이동/첨부/발송/답장/전달/폴더/진행바) |
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [UML[계획]-user-mail.md](./UML[계획]-user-mail.md): 아키텍처 및 설계
|
||||
Reference in New Issue
Block a user