1. 프로젝트 개요
항목 | 내용 |
프로젝트명 | DocuFlow |
프로젝트 설명 | PDF 파일 처리 기능을 REST API로 제공하는 SaaS 플랫폼 |
목표 | TDD 기반 개발로 안정적인 PDF 처리 API 서비스
구축 및 수익화 |
기술 스택 | Spring Boot 3.x, Java 17, PostgreSQL, JUnit5, Mockito, AWS S3 |
개발 기간 | 3개월 (MVP) |
요금제 정의
티어 | 월 요금 | 일일 호출 한도 | 월간 호출 한도 | 파일 크기 제한 |
Free | 0원 | 50회 | 500회 | 10MB |
Basic | 9,900원 | 500회 | 10,000회 | 50MB |
Pro | 29,900원 | 무제한 | 100,000회 | 100MB |
2. Member 도메인
ID | 기능명 | 우선순위 | 설명 |
MEM-001 | 회원가입 | P0 | 이메일, 비밀번호로 회원가입 |
MEM-002 | 로그인 | P0 | 이메일, 비밀번호로 로그인 후 JWT 발급 |
MEM-003 | 로그아웃 | P0 | 토큰 무효화 처리 |
MEM-004 | 내 정보 조회 | P1 | 본인 회원 정보 조회 |
MEM-005 | 내 정보 수정 | P1 | 이름, 연락처 등 수정 |
MEM-006 | 이메일 인증 | P1 | 가입 시 이메일 검증 |
MEM-007 | 비밀번호 재설정 | P1 | 이메일 통한 재설정 |
MEM-008 | 소셜 로그인 | P2 | Google, GitHub OAuth |
MEM-009 | 회원 탈퇴 | P2 | 계정 삭제 (soft delete) |
MEM-001: 회원가입
•
요구사항
항목 | 내용 |
설명 | 신규 사용자가 이메일과 비밀번호로 계정을 생성한다 |
선행 조건 | 없음 |
후행 조건 | 회원 정보 저장, 이메일 인증 메일 발송,
Free 요금제 자동 적용 |
•
입력 데이터
필드 | 타입 | 필수 | 검증 규칙 |
email | String | O | 이메일 형식, 최대 100자,
중복 불가 |
password | String | O | 최소 8자, 영문+숫자+특수문자 포함 |
name | String | O | 최소 2자, 최대 50자 |
•
비즈니스 규칙
◦
BR-001: 이미 가입된 이메일로는 가입 불가
◦
BR-002: 비밀번호는 BCrpyt로 암호화하여 저장
◦
BR-003: 가입 즉시 Free 요금제 자동 적용
◦
BR-004: 가입 완료 시 이메일 인증 메일 발송 (P1에서 구현)
•
API 엔드포인트
POST /api/v1/members/signup
JSON
복사
•
응답
◦
성공: 201 Created
◦
실패: 400 Bad Request(검증 실패), 409 Conflict(이메일 중복)
MEM-002: 로그인
•
요구사항
항목 | 내용 |
설명 | 가입된 사용자가 이메일과 비밀번호로 로그인하여 JWT 토큰을 발급받는다 |
선행 조건 | 회원가입 완료 |
후행 조건 | Access Token, Refresh Token 발급 |
•
입력 데이터
필드 | 타입 | 필수 | 검증 규칙 |
email | String | O | 이메일 형식 |
password | String | O | 빈 값 불가 |
•
비즈니스 규칙
◦
BR-005: 이메일 또는 비밀번호 불일치 시 동일한 에러 메시지 반환 (보안)
◦
BR-006: 정지된 회원은 로그인 불가
◦
BR-007: Access Token 유효기간 30분, Refresh Token 유효기간 7일
•
API 엔드포인트
POST /api/v1/members/login
JSON
복사
•
응답
◦
성공: 200 OK (accessToken, refreshToken, expiresIn 반환)
◦
실패: 401 Unauthorized
MEM-003: 로그아웃
•
요구사항
항목 | 내용 |
설명 | 로그인된 사용자가 로그아웃하여 토큰을 무효화한다 |
선행 조건 | 로그인 상태 |
후행 조건 | Refresh Token 무효화 |
•
비즈니스 규칙
◦
BR-008: RefreshToken 을 블랙리스트에 등록하여 재사용 방지
•
API 엔드포인트
POST /api/v1/members/logout
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패: 401 Unauthorized
MEM-004: 내 정보 조회
•
요구사항
항목 | 내용 |
설명 | 로그인한 사용자가 본인의 회원 정보를 조회한다 |
선행 조건 | 로그인 상태 |
후행 조건 | 없음 |
•
응답 데이터
필드 | 타입 | 설명 |
id | Long | 회원 ID |
email | String | 이메일 |
name | String | 이름 |
planType | String | 현재 요금제 (FREE/BASIC/PRO) |
emailVerified | Boolean | 이메일 인증 여부 |
createdAt | DateTime | 가입일시 |
•
API 엔드포인트
GET /api/v1/members/me
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패: 401 Unauthorized
MEM-005: 내 정보 수정
•
요구사항
항목 | 내용 |
설명 | 로그인한 사용자가 본인의 정보를 수정한다 |
선행 조건 | 로그인 상태 |
후행 조건 | 회원 정보 업데이트 |
•
입력 데이터
필드 | 타입 | 필수 | 검증 규칙 |
name | String | X | 최소 2자, 최대 50자 |
currentPassword | String | X | 비밀번호 변경 시 필수 |
newPassword | String | X | 최소 8자, 영문 + 숫자 +
특수문자 포함 |
•
비즈니스 규칙
◦
BR-009: 비밀번호 변경 시 현재 비밀번호 확인 필수
◦
BR-010: 이메일 변경 불가 (변경 필요 시 별도 프로세스)
•
API 엔드포인트
PATCH /api/v1/members/me
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패: 400 Bad Request, 401 Unauthorized
나머지 기능들은 MVP 구현 완료 이후 진행할 예정
3. ApiKey (API 키) 도메인
ID | 기능명 | 우선순위 | 설명 |
KEY-001 | API Key 발급 | P0 | 회원이 API Key를 생성한다 |
KEY-002 | API Key 목록 조회 | P0 | 본인의 API Key 목록을 조회한다 |
KEY-003 | API Key 재발급 | P1 | 기존 Key 폐기 후 신규 발급 |
KEY-004 | API Key 비활성화 | P1 | 특정 Key를 일시 중지한다 |
KEY-005 | API Key 활성화 | P1 | 비활성화된 Key를 다시 활성화한다 |
KEY-006 | API Key 삭제 | P1 | Key를 영구 삭제한다 |
KEY-001: API Key 발급
•
요구사항
항목 | 내용 |
설명 | 로그인한 회원이 PDF API 호출에 사용할 API Key를 발급받는다 |
선행 조건 | 로그인 상태, 이메일 인증 완료 (P1 구현 후 적용) |
후행 조건 | 새로운 API Key 생성 및 저장 |
•
입력 데이터
필드 | 타입 | 필수 | 검증 규칙 |
keyName | String | O | 최소 1자, 최대 50자 |
•
비즈니스 규칙
◦
BR-011: 회원당 최대 5개의 API Key 발급 가능
◦
BR-012: API Key는 df_live_ 접두사 + 32자리 랜덤 문자열로 생성
◦
BR-013: API Key 원본은 발급 시점에만 노출, 이후에는 마스킹 처리 (df_live_xxxx...xxxx)
◦
BR-014: API Key는 SHA-256 해시로 저장
•
API 엔드포인트
POST /api/v1/api-keys
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 201 Created (최초 1회만 원본 Key 반환)
◦
실패: 400 Bad Request, 401 Unauthorized, 403 Forbidden (한도 초과)
KEY-002: API Key 목록 조회
•
요구사항
항목 | 내용 |
설명 | 로그인한 회원이 본인의 API Key 목록을 조회한다 |
선행 조건 | 로그인 상태 |
후행 조건 | 없음 |
•
응답 데이터 (목록 항목)
필드 | 타입 | 설명 |
id | Long | API Key ID |
keyName | String | Key 별칭 |
maskedKey | String | 마스킹된 Key (df_live_xxxx...xxxx) |
status | String | 상태 (ACTIVE / INACTIVE) |
lastUsedAt | DateTime | 마지막 사용 일시 (nullable) |
createdAt | DateTime | 생성 일시 |
•
비즈니스 규칙
◦
BR-015: API Key 원본은 절대 반환하지 않음 (마스킹 처리)
◦
BR-016: 삭제된 Key는 목록에 표시되지 않음
•
API 엔드포인트
GET /api/v1/api-keys
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패: 401 Unauthorized
KEY-003: API Key 재발급
•
요구사항
항목 | 내용 |
설명 | 기존 API Key를 폐기하고 동일한 이름으로 새 Key를 발급한다 |
선행 조건 | 로그인 상태, 해당 Key의 소유자 |
후행 조건 | 기존 Key 삭제, 신규 Key 생성 |
•
비즈니스 규칙
◦
BR-017: 재발급 시 기존 Key는 즉시 무효화
◦
BR-018: 재발급된 Key는 기존 keyName을 유지
◦
BR-019: 재발급 후 원본 Key는 최초 1회만 노출
•
API 엔드포인트
POST /api/v1/api-keys/{keyId}/regenerate
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK (새 원본 Key 반환)
◦
실패: 401 Unauthorized, 403 Forbidden (본인 Key 아님), 404 Not Found
KEY-004: API Key 비활성화
•
요구사항
항목 | 내용 |
설명 | 특정 API Key를 일시적으로 사용 중지한다 |
선행 조건 | 로그인 상태, 해당 Key의 소유자, Key 상태가 ACTIVE |
후행 조건 | Key 상태가 INACTIVE로 변경 |
•
비즈니스 규칙
◦
BR-020: 비활성화된 Key로 API 호출 시 401 에러 반환
◦
BR-021: 이미 비활성화된 Key는 재비활성화 불가 (400 에러)
•
엔드포인트
PATCH /api/v1/api-keys/{keyId}/deactivate
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패:
▪
400 Bad Request (이미 비활성)
▪
401 Unauthorized
▪
403 Forbidden
▪
404 Not Found
KEY-005: API Key 활성화
•
요구사항
항목 | 내용 |
설명 | 비활성화된 API Key를 다시 활성화한다 |
선행 조건 | 로그인 상태, 해당 Key의 소유자, Key 상태가 INACTIVE |
후행 조건 | Key 상태가 ACTIVE로 변경 |
•
비즈니스 규칙
◦
BR-022: 이미 활성화된 Key는 재활성화 불가 (400 에러)
•
API 엔드포인트
PATCH /api/v1/api-keys/{keyId}/activate
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 200 OK
◦
실패:
▪
400 Bad Request (이미 비활성)
▪
401 Unauthorized
▪
403 Forbidden
▪
404 Not Found
KEY-006: API Key 삭제
•
요구사항
항목 | 내용 |
설명 | API Key를 영구적으로 삭제한다 |
선행 조건 | 로그인 상태, 해당 Key의 소유자 |
후행 조건 | Key 영구 삭제 (Hard Delete) |
•
비즈니스 규칙
◦
BR-023: 삭제된 Key는 복구 불가
◦
BR-024: 삭제된 Key로 API 호출 시 401 에러 반환
•
API 엔드포인트
DELETE /api/v1/api-keys/{keyId}
Authorization: Bearer {accessToken}
JSON
복사
•
응답
◦
성공: 204 No Content
◦
실패: 401 Unauthorized, 403 Forbidden, 404 Not Found

