{ "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"] } } }