SAM E-Sign 테스트 계획서
프로젝트명: SAM E-Sign (전자계약 서명 솔루션)
작성일: 2026-02-12
버전: v1.0
작성자: DX 추진팀
상태: 구현 완료 / 테스트 대기
1. 테스트 개요
1.1 목적
SAM E-Sign v1.0의 모든 기능이 요구사항 정의서(FR-001FR-012, NFR-001NFR-007)에 부합하는지 검증한다.
1.2 테스트 범위
| 범위 |
대상 |
테스트 유형 |
| API 엔드포인트 |
16개 (인증 10 + 공개 6) |
단위, 통합 |
| MNG 화면 |
8개 (인증 5 + 공개 3) |
E2E, UI |
| 핵심 플로우 |
계약 생성 → 서명 완료 |
통합, 시나리오 |
| 보안 |
OTP, 토큰, 해시, 접근제어 |
보안 |
| 비기능 |
성능, 호환성, 다중 테넌트 |
비기능 |
1.3 테스트 환경
| 항목 |
설정 |
| API 서버 |
docker exec sam-api-1 (Laravel 11, PHP 8.3) |
| MNG 서버 |
docker exec sam-mng-1 (Laravel 11, PHP 8.3) |
| DB |
sam-mysql-1 (MySQL 8.0) |
| 브라우저 |
Chrome 최신, Safari 최신, Firefox 최신 |
| 모바일 |
Chrome Mobile, Safari iOS |
| 테스트 도구 |
Postman (API), 브라우저 DevTools (UI) |
1.4 테스트 데이터
| 항목 |
값 |
| 테스트 테넌트 |
tenant_id = 1 |
| 테스트 사용자 (갑) |
기존 로그인 계정 사용 |
| 테스트 상대방 (을) |
test-signer@example.com |
| 테스트 PDF |
1~3페이지, 5MB 이하 |
| 대용량 PDF |
정확히 20MB |
| 초과 PDF |
21MB (거부 확인용) |
2. API 테스트 케이스 - 계약 관리 (인증 필요)
TC-API-001: 계약 목록 조회
엔드포인트: GET /api/v1/esign/contracts
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
기본 목록 조회 |
파라미터 없음 |
200, 페이지네이션 응답 (기본 20건) |
P1 |
| 2 |
상태 필터 |
?status=draft |
200, draft 상태만 반환 |
P1 |
| 3 |
검색 |
?search=테스트 |
200, 제목에 "테스트" 포함된 건만 반환 |
P1 |
| 4 |
날짜 범위 |
?date_from=2026-02-01&date_to=2026-02-28 |
200, 해당 기간 내 계약만 반환 |
P2 |
| 5 |
페이지네이션 |
?page=2&size=5 |
200, 5건씩 2페이지 반환 |
P2 |
| 6 |
비인증 접근 |
Authorization 헤더 없음 |
401 Unauthorized |
P1 |
| 7 |
다른 테넌트 데이터 격리 |
다른 tenant_id 사용자로 접근 |
200, 해당 테넌트 데이터만 반환 |
P1 |
TC-API-002: 계약 생성
엔드포인트: POST /api/v1/esign/contracts
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 생성 |
모든 필수 필드 + PDF |
201, contract_code 자동 생성, status=draft |
P1 |
| 2 |
제목 누락 |
title 없음 |
422, validation 에러 |
P1 |
| 3 |
PDF 누락 |
file 없음 |
422, validation 에러 |
P1 |
| 4 |
PDF 형식 아님 |
.docx 파일 업로드 |
422, "mimes:pdf" 에러 |
P1 |
| 5 |
PDF 20MB 초과 |
21MB 파일 |
422, "max:20480" 에러 |
P1 |
| 6 |
상대방 이름 누락 |
counterpart_name 없음 |
422, validation 에러 |
P1 |
| 7 |
상대방 이메일 형식 오류 |
"invalid-email" |
422, email validation 에러 |
P1 |
| 8 |
서명 순서 지정 |
sign_order_type=creator_first |
201, 작성자 먼저 서명 순서 |
P2 |
| 9 |
만료일 과거 |
expires_at=2026-01-01 |
422, "after:now" 에러 |
P2 |
| 10 |
제목 200자 초과 |
201자 제목 |
422, "max:200" 에러 |
P3 |
| 11 |
SHA-256 해시 생성 확인 |
정상 PDF |
201, original_file_hash 64자 |
P1 |
| 12 |
서명자 2인 자동 생성 |
정상 생성 |
201, signers 배열 2개 (creator, counterpart) |
P1 |
| 13 |
access_token 유일성 |
연속 2건 생성 |
각 서명자의 access_token이 모두 다름 |
P1 |
TC-API-003: 계약 상세 조회
엔드포인트: GET /api/v1/esign/contracts/{id}
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 조회 |
존재하는 id |
200, signers + signFields + auditLogs 포함 |
P1 |
| 2 |
존재하지 않는 id |
id=99999 |
404, "계약을 찾을 수 없습니다" |
P1 |
| 3 |
다른 테넌트 계약 |
다른 테넌트의 계약 id |
404 (테넌트 격리) |
P1 |
| 4 |
삭제된 계약 |
soft deleted 계약 id |
404 |
P2 |
| 5 |
access_token 미노출 |
정상 조회 |
signers의 access_token, otp_code 필드 없음 |
P1 |
TC-API-004: 계약 취소
엔드포인트: POST /api/v1/esign/contracts/{id}/cancel
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
draft 상태 취소 |
status=draft |
200, status→cancelled |
P1 |
| 2 |
pending 상태 취소 |
status=pending |
200, status→cancelled |
P1 |
| 3 |
completed 상태 취소 시도 |
status=completed |
400/422, "현재 상태에서 취소 불가" |
P1 |
| 4 |
expired 상태 취소 시도 |
status=expired |
400/422, 상태 변경 불가 |
P2 |
| 5 |
이미 cancelled 상태 |
status=cancelled |
400/422, 중복 취소 방지 |
P2 |
| 6 |
감사 로그 생성 확인 |
정상 취소 |
audit_logs에 'cancelled' 액션 기록 |
P1 |
TC-API-005: 서명 필드 설정
엔드포인트: POST /api/v1/esign/contracts/{id}/fields
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 설정 (서명 2개) |
갑/을 서명 필드 각 1개 |
200, fields 2개 저장 |
P1 |
| 2 |
다양한 필드 타입 |
signature + date + text |
200, 3개 저장 |
P1 |
| 3 |
빈 배열 |
fields=[] |
422, "min:1" 에러 |
P1 |
| 4 |
좌표 범위 초과 |
position_x=150 |
422, "between:0,100" 에러 |
P1 |
| 5 |
음수 좌표 |
position_x=-10 |
422, validation 에러 |
P2 |
| 6 |
유효하지 않은 signer_id |
signer_id=99999 |
422, "exists" 에러 |
P1 |
| 7 |
유효하지 않은 field_type |
field_type="invalid" |
422, enum 에러 |
P2 |
| 8 |
pending 상태에서 설정 시도 |
status=pending |
400/422, "draft 상태에서만 가능" |
P1 |
| 9 |
기존 필드 교체 확인 |
2번째 설정 요청 |
기존 필드 삭제 + 새 필드 생성 |
P1 |
| 10 |
페이지 번호 0 |
page_number=0 |
422, "min:1" 에러 |
P2 |
TC-API-006: 서명 요청 발송
엔드포인트: POST /api/v1/esign/contracts/{id}/send
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 발송 |
draft 상태 + 필드 설정 완료 |
200, status→pending, 이메일 발송 |
P1 |
| 2 |
필드 미설정 상태 발송 |
필드 0개 |
400, "서명 필드를 먼저 설정해주세요" |
P1 |
| 3 |
pending 상태에서 재발송 |
status=pending |
400, "이미 발송된 계약" |
P1 |
| 4 |
첫 서명자 상태 변경 확인 |
counterpart_first |
상대방 signer status→notified |
P1 |
| 5 |
이메일 내용 확인 |
정상 발송 |
계약 제목, 서명 링크, 만료일 포함 |
P2 |
| 6 |
감사 로그 확인 |
정상 발송 |
'sent' 액션 기록 |
P1 |
TC-API-007: 리마인더 발송
엔드포인트: POST /api/v1/esign/contracts/{id}/remind
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 리마인더 |
pending 상태 |
200, 리마인더 이메일 발송 |
P1 |
| 2 |
draft 상태 리마인더 |
status=draft |
400, 발송 전 상태 |
P2 |
| 3 |
completed 상태 리마인더 |
status=completed |
400, 완료 상태에서 불가 |
P2 |
| 4 |
감사 로그 확인 |
정상 발송 |
'reminded' 액션 기록 |
P2 |
TC-API-008: 계약 통계
엔드포인트: GET /api/v1/esign/contracts/stats
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 통계 조회 |
없음 |
200, 상태별 카운트 7개 (total, draft, pending 등) |
P1 |
| 2 |
데이터 없을 때 |
계약 0건 |
200, 모든 값 0 |
P2 |
| 3 |
테넌트 격리 |
다른 테넌트 |
해당 테넌트 데이터만 집계 |
P1 |
TC-API-009: 완료 PDF 다운로드
엔드포인트: GET /api/v1/esign/contracts/{id}/download
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 다운로드 |
completed 상태 |
200, Content-Type: application/pdf |
P1 |
| 2 |
미완료 상태 |
status=pending |
400, "완료된 계약만 다운로드 가능" |
P1 |
| 3 |
비인증 접근 |
Authorization 없음 |
401 |
P1 |
| 4 |
감사 로그 확인 |
정상 다운로드 |
'downloaded' 액션 기록 |
P2 |
TC-API-010: 문서 무결성 검증
엔드포인트: GET /api/v1/esign/contracts/{id}/verify
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 검증 (무결) |
변경 없는 파일 |
200, original_integrity=true |
P1 |
| 2 |
위변조된 파일 |
파일 직접 변경 |
200, original_integrity=false |
P1 |
| 3 |
해시값 포함 확인 |
정상 검증 |
original_hash, signed_hash 반환 |
P1 |
3. API 테스트 케이스 - 서명 프로세스 (토큰 기반)
TC-API-011: 토큰으로 계약 조회
엔드포인트: GET /api/v1/esign/sign/{token}
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
유효한 토큰 접속 |
정상 access_token |
200, 계약 정보 + 서명자 정보 반환 |
P1 |
| 2 |
유효하지 않은 토큰 |
"invalid-token-xxx" |
404, "유효하지 않은 링크" |
P1 |
| 3 |
만료된 토큰 |
token_expires_at 경과 |
400, "서명 링크가 만료되었습니다" |
P1 |
| 4 |
취소된 계약 토큰 |
status=cancelled |
400, "취소된 계약" |
P1 |
| 5 |
이미 서명 완료된 토큰 |
signer status=signed |
400, "이미 서명 완료" |
P1 |
| 6 |
서명 순서 아닌 서명자 |
두 번째 순서 서명자 |
400, "아직 차례가 아닙니다" 또는 대기 안내 |
P1 |
TC-API-012: OTP 발송
엔드포인트: POST /api/v1/esign/sign/{token}/otp/send
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 OTP 발송 |
유효한 토큰 |
200, "인증코드가 발송되었습니다", expires_in=300 |
P1 |
| 2 |
OTP 재발송 |
이전 OTP 만료 후 |
200, 새 OTP 발송 |
P1 |
| 3 |
유효하지 않은 토큰 |
잘못된 토큰 |
404 |
P1 |
| 4 |
OTP 시도 횟수 초과 후 |
5회 실패 이후 발송 |
400, "인증 횟수 초과" |
P1 |
TC-API-013: OTP 인증
엔드포인트: POST /api/v1/esign/sign/{token}/otp/verify
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 인증 |
올바른 OTP 코드 |
200, verified=true, sign_session_token 발급 |
P1 |
| 2 |
잘못된 OTP |
틀린 코드 |
401, verified=false, remaining_attempts 감소 |
P1 |
| 3 |
OTP 만료 |
5분 경과 후 입력 |
401, "인증코드가 만료되었습니다" |
P1 |
| 4 |
5회 시도 초과 |
6번째 시도 |
400, "OTP 입력 횟수를 초과했습니다" |
P1 |
| 5 |
OTP 없이 인증 |
otp_code 미전송 |
422, validation 에러 |
P2 |
| 6 |
인증 후 auth_verified_at 기록 |
정상 인증 |
DB에 인증 시각 저장 |
P1 |
| 7 |
감사 로그 확인 (성공) |
정상 인증 |
'authenticated' 액션 기록 |
P1 |
| 8 |
감사 로그 확인 (실패) |
잘못된 OTP |
'otp_failed' 또는 시도 횟수 기록 |
P2 |
TC-API-014: PDF 문서 조회
엔드포인트: GET /api/v1/esign/sign/{token}/document
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
인증 후 문서 조회 |
유효한 토큰 + sign_session_token |
200, application/pdf 스트리밍 |
P1 |
| 2 |
인증 전 문서 접근 |
sign_session_token 없음 |
401 또는 403 |
P1 |
| 3 |
감사 로그 확인 |
정상 조회 |
'viewed' 액션 기록 |
P2 |
TC-API-015: 서명 제출
엔드포인트: POST /api/v1/esign/sign/{token}/submit
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 서명 제출 |
base64 서명 이미지 |
200, signer status→signed, signed_at 기록 |
P1 |
| 2 |
서명 이미지 누락 |
signature_image 없음 |
422, validation 에러 |
P1 |
| 3 |
인증 전 서명 시도 |
sign_session_token 없음 |
401 또는 403 |
P1 |
| 4 |
이미 서명한 서명자 |
status=signed |
400, "이미 서명 완료" |
P1 |
| 5 |
IP/UserAgent 기록 확인 |
정상 제출 |
sign_ip_address, sign_user_agent 저장 |
P1 |
| 6 |
첫 서명 → partially_signed |
첫 번째 서명자 서명 |
contract status→partially_signed |
P1 |
| 7 |
두 번째 서명 → completed |
두 번째 서명자 서명 |
contract status→completed, completed_at 기록 |
P1 |
| 8 |
다음 서명자 알림 |
첫 서명 완료 |
다음 서명자에게 이메일 발송 |
P1 |
| 9 |
감사 로그 확인 |
정상 서명 |
'signed' 액션 + IP/UA 기록 |
P1 |
TC-API-016: 서명 거절
엔드포인트: POST /api/v1/esign/sign/{token}/reject
| # |
시나리오 |
입력 |
기대 결과 |
우선순위 |
| 1 |
정상 거절 |
reason="조건 수정 필요" |
200, signer status→rejected, contract status→rejected |
P1 |
| 2 |
사유 누락 |
reason 없음 |
422, validation 에러 |
P1 |
| 3 |
사유 1000자 초과 |
1001자 텍스트 |
422, "max:1000" 에러 |
P2 |
| 4 |
이미 서명한 서명자 거절 |
status=signed |
400, "이미 서명 완료" |
P1 |
| 5 |
감사 로그 확인 |
정상 거절 |
'rejected' 액션 + 거절 사유 metadata |
P1 |
4. E2E 시나리오 테스트
TC-E2E-001: 정상 계약 플로우 (상대방 먼저)
시나리오: 계약 생성 → 필드 설정 → 발송 → 상대방 서명 → 작성자 서명 → 완료
| 단계 |
행위 |
검증 포인트 |
| 1 |
A: 계약 생성 (PDF 업로드 + 정보 입력) |
status=draft, 서명자 2인 생성, 해시 생성 |
| 2 |
A: 서명 필드 설정 (갑/을 각 1개) |
fields 2개 저장 |
| 3 |
A: 서명 요청 발송 |
status→pending, 을에게 이메일 |
| 4 |
B: 서명 링크 접속 |
계약 정보 표시 |
| 5 |
B: OTP 발송 요청 |
OTP 이메일 발송 |
| 6 |
B: OTP 입력 → 인증 |
sign_session_token 발급 |
| 7 |
B: 계약서 확인 (PDF 렌더링) |
PDF 정상 표시, 서명 위치 하이라이트 |
| 8 |
B: 서명 수행 |
signer status→signed, contract→partially_signed |
| 9 |
A: 알림 수신 |
"상대방이 서명했습니다" 이메일 |
| 10 |
A: 서명 링크 접속 → OTP → 서명 |
signer status→signed |
| 11 |
자동 완료 처리 |
contract→completed, completed_at 기록 |
| 12 |
양쪽에 완료 알림 |
완료 이메일 + 다운로드 링크 |
| 13 |
A: PDF 다운로드 |
Content-Type: application/pdf |
| 14 |
A: 무결성 검증 |
integrity=true |
TC-E2E-002: 정상 계약 플로우 (작성자 먼저)
시나리오: sign_order_type=creator_first로 생성
| 단계 |
행위 |
검증 포인트 |
| 1 |
A: 계약 생성 (creator_first) |
작성자 sign_order=1 |
| 2 |
A: 필드 설정 + 발송 |
작성자에게 먼저 이메일 |
| 3 |
A: 서명 수행 |
contract→partially_signed |
| 4 |
B: 알림 수신 → 서명 수행 |
contract→completed |
TC-E2E-003: 서명 거절 플로우
| 단계 |
행위 |
검증 포인트 |
| 1 |
A: 계약 생성 → 필드 설정 → 발송 |
status=pending |
| 2 |
B: 서명 링크 접속 → OTP 인증 |
인증 완료 |
| 3 |
B: 서명 거절 (사유 입력) |
signer→rejected, contract→rejected |
| 4 |
A: 거절 알림 수신 |
거절 사유 확인 가능 |
| 5 |
이후 서명 시도 |
거절된 계약 서명 불가 확인 |
TC-E2E-004: 계약 취소 플로우
| 단계 |
행위 |
검증 포인트 |
| 1 |
A: 계약 생성 → 발송 |
status=pending |
| 2 |
A: 계약 취소 |
status→cancelled |
| 3 |
B: 기존 서명 링크 접속 |
"취소된 계약" 메시지 표시 |
| 4 |
A: 대시보드에서 상태 확인 |
cancelled 표시 |
TC-E2E-005: 리마인더 발송 플로우
| 단계 |
행위 |
검증 포인트 |
| 1 |
A: 계약 발송 (pending 상태) |
서명 대기 중 |
| 2 |
A: 리마인더 발송 |
이메일 재발송 |
| 3 |
감사 로그 확인 |
'reminded' 기록 |
5. 보안 테스트 케이스
TC-SEC-001: 토큰 보안
| # |
시나리오 |
검증 방법 |
기대 결과 |
우선순위 |
| 1 |
토큰 추측 공격 |
랜덤 128자 토큰으로 접속 |
404, 접근 차단 |
P1 |
| 2 |
토큰 재사용 방지 |
서명 완료 후 같은 토큰 접속 |
400, "이미 서명 완료" |
P1 |
| 3 |
토큰 만료 |
token_expires_at 이후 접속 |
400, "링크 만료" |
P1 |
| 4 |
API 응답에 토큰 미포함 |
계약 상세 API 호출 |
signers에 access_token 필드 없음 |
P1 |
TC-SEC-002: OTP 보안
| # |
시나리오 |
검증 방법 |
기대 결과 |
우선순위 |
| 1 |
브루트포스 방지 |
6번째 OTP 시도 |
인증 차단 |
P1 |
| 2 |
OTP 시간 만료 |
5분 경과 후 입력 |
"인증코드 만료" |
P1 |
| 3 |
이전 OTP 재사용 |
재발송 후 이전 코드 입력 |
인증 실패 |
P1 |
| 4 |
OTP 탈취 방지 |
API 응답에서 OTP 코드 확인 |
OTP 코드가 응답에 포함되지 않음 |
P1 |
TC-SEC-003: 접근 제어
| # |
시나리오 |
검증 방법 |
기대 결과 |
우선순위 |
| 1 |
다른 테넌트 계약 접근 |
타 테넌트 contract_id로 API 호출 |
404 (데이터 격리) |
P1 |
| 2 |
비인증 사용자 관리 API 접근 |
Authorization 없이 계약 관리 API |
401 |
P1 |
| 3 |
인증 전 서명 시도 |
sign_session_token 없이 submit |
401/403 |
P1 |
| 4 |
다른 서명자의 토큰 사용 |
A의 토큰으로 B의 서명 시도 |
400/403, 불일치 |
P1 |
| 5 |
서명 순서 우회 시도 |
두 번째 순서 서명자가 먼저 접근 |
400, "차례가 아닙니다" |
P1 |
TC-SEC-004: 문서 무결성
| # |
시나리오 |
검증 방법 |
기대 결과 |
우선순위 |
| 1 |
원본 PDF 해시 검증 |
verify API 호출 |
original_integrity=true |
P1 |
| 2 |
위변조 감지 |
스토리지에서 파일 직접 수정 후 검증 |
original_integrity=false |
P1 |
| 3 |
해시 비교 시 타이밍 공격 방지 |
hash_equals() 사용 여부 확인 |
코드 리뷰로 확인 |
P2 |
TC-SEC-005: 감사 추적
| # |
시나리오 |
검증 방법 |
기대 결과 |
우선순위 |
| 1 |
모든 행위 기록 |
전체 플로우 수행 후 로그 확인 |
모든 주요 액션 기록됨 |
P1 |
| 2 |
IP/UserAgent 기록 |
서명 시 환경 정보 |
정확한 IP/UA 기록 |
P1 |
| 3 |
감사 로그 삭제 불가 |
DELETE 시도 |
SoftDeletes 미적용, 삭제 API 없음 |
P1 |
| 4 |
로그 timestamp 정확성 |
서명 시각 기록 |
서버 시간 기준 정확 기록 |
P2 |
6. MNG 화면 테스트 케이스
TC-UI-001: 대시보드 (/esign)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
화면 로딩 |
React 컴포넌트 정상 마운트 (#esign-dashboard-root) |
P1 |
| 2 |
통계 카드 표시 |
상태별 건수 (전체, 진행중, 완료 등) 표시 |
P1 |
| 3 |
계약 목록 표시 |
테이블 형태 목록 (제목, 상태, 서명자, 날짜) |
P1 |
| 4 |
상태 필터 |
상태 클릭 시 해당 상태 계약만 필터링 |
P2 |
| 5 |
검색 |
제목 검색 동작 |
P2 |
| 6 |
"새 계약" 버튼 |
/esign/create로 이동 |
P1 |
| 7 |
계약 행 클릭 |
/esign/{id}로 이동 |
P1 |
| 8 |
HTMX 네비게이션 |
사이드바에서 클릭 시 HX-Redirect로 전체 페이지 로드 |
P1 |
TC-UI-002: 계약 생성 (/esign/create)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
화면 로딩 |
React 컴포넌트 정상 마운트 |
P1 |
| 2 |
PDF 업로드 영역 |
드래그&드롭 또는 파일 선택 |
P1 |
| 3 |
PDF 미리보기 |
업로드 후 파일명/크기 표시 |
P2 |
| 4 |
필수 필드 표시 |
제목, PDF, 이름, 이메일에 필수 마크 |
P1 |
| 5 |
유효성 검증 |
빈 필드 제출 시 에러 메시지 |
P1 |
| 6 |
이메일 형식 검증 |
잘못된 이메일 입력 시 에러 |
P2 |
| 7 |
생성 완료 |
생성 후 필드 설정 화면으로 이동 |
P1 |
TC-UI-003: 서명 위치 지정 (/esign/{id}/fields)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
PDF.js 렌더링 |
업로드한 PDF 정상 표시 |
P1 |
| 2 |
페이지 이동 |
다중 페이지 PDF 페이지 전환 |
P1 |
| 3 |
서명 필드 추가 |
클릭으로 서명란 배치 |
P1 |
| 4 |
서명자 구분 |
갑(파랑)/을(빨강) 색상 구분 |
P2 |
| 5 |
드래그로 위치 이동 |
필드 드래그 이동 |
P1 |
| 6 |
필드 크기 조절 |
리사이즈 핸들 동작 |
P2 |
| 7 |
필드 삭제 |
필드 선택 후 삭제 |
P1 |
| 8 |
저장 |
API 호출 후 저장 완료 메시지 |
P1 |
TC-UI-004: 서명 요청 발송 (/esign/{id}/send)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
체크리스트 표시 |
서명자 정보, 필드 수, PDF 확인 |
P1 |
| 2 |
서명 순서 표시 |
누가 먼저 서명하는지 명확 표시 |
P1 |
| 3 |
발송 버튼 |
클릭 시 확인 다이얼로그 → API 호출 |
P1 |
| 4 |
발송 완료 |
성공 메시지 + 대시보드로 이동 |
P1 |
TC-UI-005: 계약 상세 (/esign/{id})
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
기본 정보 표시 |
제목, 코드, 상태, 날짜 |
P1 |
| 2 |
서명자 현황 |
갑/을 서명 상태 (대기/완료/거절) |
P1 |
| 3 |
감사 로그 타임라인 |
시간순 이벤트 목록 |
P1 |
| 4 |
취소 버튼 |
draft/pending 상태에서 노출, 취소 확인 |
P1 |
| 5 |
다운로드 버튼 |
completed 상태에서만 노출 |
P1 |
| 6 |
리마인더 버튼 |
pending/partially_signed에서 노출 |
P2 |
TC-UI-006: 본인인증 OTP (/esign/sign/{token})
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
계약 정보 표시 |
제목, 서명 요청자, 기한 |
P1 |
| 2 |
OTP 발송 버튼 |
클릭 시 이메일 발송 |
P1 |
| 3 |
OTP 입력 필드 |
6자리 입력 UI |
P1 |
| 4 |
타이머 표시 |
남은 시간 카운트다운 (5분) |
P2 |
| 5 |
에러 메시지 |
잘못된 OTP 입력 시 에러 표시 |
P1 |
| 6 |
횟수 안내 |
남은 시도 횟수 표시 |
P2 |
| 7 |
인증 성공 |
서명 화면으로 자동 이동 |
P1 |
| 8 |
재발송 버튼 |
OTP 재발송 기능 |
P2 |
TC-UI-007: 서명 수행 (/esign/sign/{token}/sign)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
PDF 렌더링 |
계약서 전체 내용 표시 |
P1 |
| 2 |
서명 위치 하이라이트 |
서명해야 할 위치 강조 표시 |
P1 |
| 3 |
SignaturePad 동작 |
터치/마우스 서명 입력 |
P1 |
| 4 |
서명 초기화 |
"다시 서명" 버튼으로 캔버스 초기화 |
P1 |
| 5 |
동의 체크박스 |
2개 체크박스 (내용 확인 + 법적 효력 동의) |
P1 |
| 6 |
제출 버튼 |
모든 체크 완료 후 활성화 |
P1 |
| 7 |
제출 완료 |
완료 화면으로 이동 |
P1 |
| 8 |
모바일 서명 |
모바일 터치로 서명 가능 |
P1 |
TC-UI-008: 서명 완료 (/esign/sign/{token}/done)
| # |
시나리오 |
검증 포인트 |
우선순위 |
| 1 |
완료 메시지 |
"서명이 완료되었습니다" 표시 |
P1 |
| 2 |
계약 정보 요약 |
계약 제목, 서명 시각 |
P2 |
| 3 |
거절 시 메시지 |
"서명이 거절되었습니다" + 사유 표시 |
P1 |
7. 비기능 테스트 케이스
TC-NFR-001: 성능
| # |
시나리오 |
기준 |
우선순위 |
| 1 |
API 응답 시간 |
목록/상세 조회 < 500ms |
P2 |
| 2 |
PDF 업로드 (20MB) |
업로드 + 해시 생성 < 5초 |
P2 |
| 3 |
OTP 이메일 발송 |
발송 요청 ~ 이메일 수신 < 30초 |
P2 |
| 4 |
동시 접속 |
10명 동시 서명 시 에러 없음 |
P3 |
TC-NFR-002: 브라우저 호환성
| # |
브라우저 |
테스트 대상 |
우선순위 |
| 1 |
Chrome 최신 (Desktop) |
전체 기능 |
P1 |
| 2 |
Safari 최신 (Desktop) |
전체 기능 |
P1 |
| 3 |
Firefox 최신 (Desktop) |
전체 기능 |
P2 |
| 4 |
Chrome (Android) |
서명 화면 (터치 서명) |
P1 |
| 5 |
Safari (iOS) |
서명 화면 (터치 서명) |
P1 |
| 6 |
Edge 최신 |
전체 기능 |
P3 |
TC-NFR-003: 다중 테넌트
| # |
시나리오 |
검증 방법 |
우선순위 |
| 1 |
데이터 격리 |
테넌트 A에서 테넌트 B 계약 조회 불가 |
P1 |
| 2 |
통계 격리 |
각 테넌트 자체 통계만 집계 |
P1 |
| 3 |
파일 격리 |
다른 테넌트의 PDF 접근 불가 |
P1 |
8. 테스트 우선순위 정의
| 우선순위 |
의미 |
실행 시점 |
| P1 (필수) |
핵심 기능, 실패 시 서비스 불가 |
매 배포 전 |
| P2 (중요) |
부가 기능, 사용 편의 관련 |
주요 변경 시 |
| P3 (권장) |
엣지 케이스, 호환성 |
분기별 |
우선순위별 테스트 케이스 수
| 우선순위 |
API TC |
UI TC |
보안 TC |
E2E TC |
NFR TC |
합계 |
| P1 |
58 |
32 |
16 |
5 |
5 |
116 |
| P2 |
20 |
12 |
2 |
0 |
5 |
39 |
| P3 |
3 |
0 |
0 |
0 |
1 |
4 |
| 합계 |
81 |
44 |
18 |
5 |
11 |
159 |
9. 테스트 실행 가이드
9.1 API 테스트 (Postman)
9.2 E2E 테스트 (브라우저)
9.3 테스트 결과 기록 양식
| TC ID |
시나리오 |
결과 |
비고 |
테스트일 |
테스터 |
| TC-API-001-1 |
기본 목록 조회 |
PASS/FAIL |
|
|
|
| TC-API-001-2 |
상태 필터 |
PASS/FAIL |
|
|
|
| ... |
... |
... |
... |
... |
... |
이 문서는 SAM E-Sign v1.0 테스트 계획서입니다. 최종 업데이트: 2026-02-12