Files
sam-api/docs/flow-tests/user-invitation-flow.json

927 lines
26 KiB
JSON

{
"name": "사용자 초대 플로우 테스트",
"description": "사용자 초대 전체 플로우 (발송/목록/수락/취소/재발송) 및 분기 상황 테스트",
"version": "1.0",
"config": {
"baseUrl": "https://api.sam.kr/api/v1",
"apiKey": "{{$env.FLOW_TESTER_API_KEY}}",
"timeout": 30000,
"stopOnFailure": false
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}",
"test_email_prefix": "flowtest",
"test_domain": "example.com"
},
"setup": {
"description": "테스트 전 초기화 - 기존 테스트 초대 정리는 수동으로 진행"
},
"flows": [
{
"id": "flow_1",
"name": "🔴 P1: 기본 초대 플로우 (role=user)",
"description": "일반 사용자 역할로 초대 발송 → 목록 확인 → 취소",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200],
"jsonPath": {
"$.access_token": "@isString"
}
}
},
{
"id": "invite_user_role",
"name": "초대 발송 (role=user)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_user_{{$timestamp}}@{{variables.test_domain}}",
"role": "user",
"message": "SAM 시스템에 합류해 주세요!"
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id",
"invitationToken": "$.data.token",
"invitedEmail": "$.data.email"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "pending",
"$.data.email": "@isString"
}
}
},
{
"id": "list_invitations",
"name": "초대 목록 조회",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"status": "pending",
"per_page": 10
},
"dependsOn": ["invite_user_role"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
},
{
"id": "cancel_invitation",
"name": "초대 취소",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite_user_role.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["list_invitations"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
},
{
"id": "flow_2",
"name": "🔴 P1: 관리자 역할 초대 (role=admin)",
"description": "관리자 역할로 초대 발송",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_admin_role",
"name": "초대 발송 (role=admin)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_admin_{{$timestamp}}@{{variables.test_domain}}",
"role": "admin",
"message": "관리자로 초대합니다."
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "pending"
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite_admin_role.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["invite_admin_role"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_3",
"name": "🔴 P1: 매니저 역할 초대 (role=manager)",
"description": "매니저 역할로 초대 발송",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_manager_role",
"name": "초대 발송 (role=manager)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_manager_{{$timestamp}}@{{variables.test_domain}}",
"role": "manager"
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "pending"
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite_manager_role.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["invite_manager_role"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_4",
"name": "🔴 P1: 초대 재발송 플로우",
"description": "초대 발송 → 재발송 → 취소",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite",
"name": "초대 발송",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_resend_{{$timestamp}}@{{variables.test_domain}}",
"role": "user"
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id",
"originalExpiresAt": "$.data.expires_at"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "resend",
"name": "초대 재발송",
"method": "POST",
"endpoint": "/users/invitations/{{invite.invitationId}}/resend",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["invite"],
"extract": {
"newExpiresAt": "$.data.expires_at"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "pending"
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["resend"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_5",
"name": "🔴 P1: 에러 케이스 - 중복 이메일 초대",
"description": "동일 이메일로 중복 초대 시도 (대기 중 초대 존재)",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "first_invite",
"name": "첫 번째 초대 발송",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_dup_{{$timestamp}}@{{variables.test_domain}}",
"role": "user"
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id",
"testEmail": "$.data.email"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "duplicate_invite",
"name": "중복 초대 발송 (실패 예상)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{first_invite.testEmail}}",
"role": "user"
},
"dependsOn": ["first_invite"],
"expect": {
"status": [400, 422],
"jsonPath": {
"$.success": false
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{first_invite.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["duplicate_invite"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_6",
"name": "🟡 P2: 목록 필터링 - 상태별",
"description": "초대 목록을 상태별로 필터링",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "list_pending",
"name": "대기 중 목록 조회",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"status": "pending"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "list_accepted",
"name": "수락된 목록 조회",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"status": "accepted"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "list_expired",
"name": "만료된 목록 조회",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"status": "expired"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "list_cancelled",
"name": "취소된 목록 조회",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"status": "cancelled"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
},
{
"id": "flow_7",
"name": "🟡 P2: 목록 정렬 옵션",
"description": "다양한 정렬 기준으로 목록 조회",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "sort_created_at_desc",
"name": "생성일 내림차순",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"sort_by": "created_at",
"sort_dir": "desc"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "sort_expires_at_asc",
"name": "만료일 오름차순",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"sort_by": "expires_at",
"sort_dir": "asc"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "sort_email_asc",
"name": "이메일 오름차순",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"sort_by": "email",
"sort_dir": "asc"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
},
{
"id": "flow_8",
"name": "🟡 P2: 이메일 검색",
"description": "이메일 키워드로 초대 검색",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "search_by_email",
"name": "이메일 검색",
"method": "GET",
"endpoint": "/users/invitations",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"query": {
"search": "flowtest"
},
"dependsOn": ["login"],
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
}
]
},
{
"id": "flow_9",
"name": "🟢 P3: 만료 기간 지정 옵션",
"description": "만료 기간을 명시적으로 지정하여 초대",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_with_expires",
"name": "14일 만료 기간으로 초대",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_expires_{{$timestamp}}@{{variables.test_domain}}",
"role": "user",
"expires_days": 14
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.expires_at": "@isString"
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite_with_expires.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["invite_with_expires"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_10",
"name": "🟢 P3: role_id로 초대 (숫자 ID 사용)",
"description": "role 문자열 대신 role_id 숫자로 초대",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_with_role_id",
"name": "role_id=2로 초대",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_roleid_{{$timestamp}}@{{variables.test_domain}}",
"role_id": 2
},
"dependsOn": ["login"],
"extract": {
"invitationId": "$.data.id"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.role_id": 2
}
}
},
{
"id": "cleanup",
"name": "초대 취소 (정리)",
"method": "DELETE",
"endpoint": "/users/invitations/{{invite_with_role_id.invitationId}}",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["invite_with_role_id"],
"expect": {
"status": [200]
}
}
]
},
{
"id": "flow_11",
"name": "🔴 P1: 에러 케이스 - 잘못된 역할",
"description": "존재하지 않는 role 값으로 초대 시도",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_invalid_role",
"name": "잘못된 role로 초대 (실패 예상)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "{{variables.test_email_prefix}}_invalid_{{$timestamp}}@{{variables.test_domain}}",
"role": "superadmin"
},
"dependsOn": ["login"],
"expect": {
"status": [400, 422],
"jsonPath": {
"$.success": false
}
}
}
]
},
{
"id": "flow_12",
"name": "🔴 P1: 에러 케이스 - 이메일 형식 오류",
"description": "잘못된 이메일 형식으로 초대 시도",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "invite_invalid_email",
"name": "잘못된 이메일로 초대 (실패 예상)",
"method": "POST",
"endpoint": "/users/invite",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"body": {
"email": "invalid-email-format",
"role": "user"
},
"dependsOn": ["login"],
"expect": {
"status": [422],
"jsonPath": {
"$.success": false
}
}
}
]
},
{
"id": "flow_13",
"name": "🔴 P1: 에러 케이스 - 권한 없이 접근",
"description": "인증 없이 초대 API 접근 시도",
"steps": [
{
"id": "invite_no_auth",
"name": "인증 없이 초대 시도 (실패 예상)",
"method": "POST",
"endpoint": "/users/invite",
"body": {
"email": "noauth@example.com",
"role": "user"
},
"expect": {
"status": [401],
"jsonPath": {
"$.success": false
}
}
},
{
"id": "list_no_auth",
"name": "인증 없이 목록 조회 (실패 예상)",
"method": "GET",
"endpoint": "/users/invitations",
"expect": {
"status": [401],
"jsonPath": {
"$.success": false
}
}
}
]
},
{
"id": "flow_14",
"name": "🔴 P1: 에러 케이스 - 존재하지 않는 초대 취소",
"description": "존재하지 않는 초대 ID로 취소 시도",
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{variables.user_id}}",
"user_pwd": "{{variables.user_pwd}}"
},
"extract": {
"accessToken": "$.access_token"
},
"expect": {
"status": [200]
}
},
{
"id": "cancel_not_found",
"name": "존재하지 않는 초대 취소 (실패 예상)",
"method": "DELETE",
"endpoint": "/users/invitations/999999",
"headers": {
"Authorization": "Bearer {{login.accessToken}}"
},
"dependsOn": ["login"],
"expect": {
"status": [404],
"jsonPath": {
"$.success": false
}
}
}
]
}
],
"summary": {
"total_flows": 14,
"priority_breakdown": {
"P1_critical": 8,
"P2_important": 3,
"P3_recommended": 3
},
"coverage": {
"endpoints": [
"POST /users/invite",
"GET /users/invitations",
"DELETE /users/invitations/{id}",
"POST /users/invitations/{id}/resend"
],
"not_covered": [
"POST /users/invitations/{token}/accept (별도 Flow 필요: 실제 이메일 수신 필요)"
]
},
"branches_tested": {
"role_types": ["admin", "manager", "user"],
"role_methods": ["role (string)", "role_id (integer)"],
"status_filters": ["pending", "accepted", "expired", "cancelled"],
"sort_options": ["created_at", "expires_at", "email"],
"error_cases": ["duplicate_email", "invalid_role", "invalid_email", "no_auth", "not_found"]
}
}
}