feat: 더미 데이터 시더 추가 및 회계 관련 마이그레이션

- DummyDataSeeder 및 개별 시더 추가 (Client, BadDebt, Deposit 등)
- payments.paid_at nullable 마이그레이션
- subscriptions 취소 컬럼 추가
- clients 테이블 bad_debt 컬럼 제거
- PlanController, ClientService 수정
- 불필요한 claudedocs, flow-test 파일 정리
This commit is contained in:
2025-12-24 08:54:52 +09:00
parent 71123128ff
commit 8686b199ee
30 changed files with 1278 additions and 2655 deletions

View File

@@ -1,172 +0,0 @@
{
"name": "ItemField is_active 컬럼 검증 테스트",
"description": "item_fields 테이블에 추가된 is_active 컬럼의 기능을 검증합니다. 필드 생성 시 기본값(true), 수정, 조회 시 is_active 필드 포함 여부를 테스트합니다.",
"version": "1.0",
"config": {
"baseUrl": "https://api.sam.kr/api/v1",
"apiKey": "{{$env.FLOW_TESTER_API_KEY}}",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}"
},
"steps": [
{
"id": "login",
"name": "1. 로그인 - 인증 토큰 획득",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{user_id}}",
"user_pwd": "{{user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.message": "로그인 성공",
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token"
}
},
{
"id": "get_fields_list",
"name": "2. 필드 목록 조회 - is_active 필드 포함 확인",
"method": "GET",
"endpoint": "/item-master/fields",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
},
"extract": {
"existingFieldId": "$.data[0].id",
"fieldCount": "$.data.length"
}
},
{
"id": "create_field",
"name": "3. 독립 필드 생성 - is_active 기본값 true 확인",
"method": "POST",
"endpoint": "/item-master/fields",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"field_name": "[테스트] is_active 검증 필드",
"field_type": "textbox",
"field_key": "test_is_active",
"is_required": false,
"placeholder": "is_active 기본값 테스트",
"description": "API Flow Tester에서 생성한 테스트 필드"
},
"expect": {
"status": [200, 201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber",
"$.data.field_name": "[테스트] is_active 검증 필드",
"$.data.is_active": true
}
},
"extract": {
"newFieldId": "$.data.id"
}
},
{
"id": "verify_field_created",
"name": "4. 생성된 필드 상세 확인 - is_active=true",
"method": "GET",
"endpoint": "/item-master/fields",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
},
"extract": {
"allFields": "$.data"
}
},
{
"id": "update_field_inactive",
"name": "5. 필드 비활성화 - is_active=false로 수정",
"method": "PUT",
"endpoint": "/item-master/fields/{{create_field.newFieldId}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"is_active": false
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.is_active": false
}
}
},
{
"id": "verify_field_inactive",
"name": "6. 비활성화 상태 확인",
"method": "GET",
"endpoint": "/item-master/fields",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "update_field_active",
"name": "7. 필드 재활성화 - is_active=true로 수정",
"method": "PUT",
"endpoint": "/item-master/fields/{{create_field.newFieldId}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"is_active": true
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.is_active": true
}
}
},
{
"id": "delete_test_field",
"name": "8. 테스트 필드 삭제 (정리)",
"method": "DELETE",
"endpoint": "/item-master/fields/{{create_field.newFieldId}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
}

View File

@@ -1,277 +0,0 @@
{
"name": "단가 관리 CRUD 테스트",
"description": "단가(Pricing) API의 생성, 조회, 수정, 확정, 삭제 전체 플로우 테스트",
"version": "1.0",
"config": {
"baseUrl": "",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}"
},
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{user_id}}",
"user_pwd": "{{user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.message": "로그인 성공",
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token"
}
},
{
"id": "list_prices",
"name": "단가 목록 조회",
"method": "GET",
"endpoint": "/pricing",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"query": {
"per_page": 10,
"page": 1
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
},
{
"id": "create_price",
"name": "단가 생성 (MATERIAL)",
"method": "POST",
"endpoint": "/pricing",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"item_type_code": "MATERIAL",
"item_id": 1,
"client_group_id": null,
"purchase_price": 10000,
"processing_cost": 500,
"loss_rate": 5,
"margin_rate": 20,
"sales_price": 12600,
"rounding_rule": "round",
"rounding_unit": 100,
"supplier": "테스트 공급업체",
"effective_from": "2025-01-01",
"effective_to": "2025-12-31",
"note": "API Flow 테스트용 단가",
"status": "draft"
},
"expect": {
"status": [201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber",
"$.data.item_type_code": "MATERIAL",
"$.data.purchase_price": 10000,
"$.data.status": "draft"
}
},
"extract": {
"price_id": "$.data.id"
}
},
{
"id": "show_price",
"name": "생성된 단가 상세 조회",
"method": "GET",
"endpoint": "/pricing/{{create_price.price_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "{{create_price.price_id}}",
"$.data.item_type_code": "MATERIAL",
"$.data.supplier": "테스트 공급업체"
}
}
},
{
"id": "update_price",
"name": "단가 수정 (가격 변경)",
"method": "PUT",
"endpoint": "/pricing/{{create_price.price_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"purchase_price": 11000,
"processing_cost": 600,
"margin_rate": 25,
"sales_price": 14500,
"note": "단가 수정 테스트",
"change_reason": "원가 인상으로 인한 가격 조정",
"status": "active"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.purchase_price": 11000,
"$.data.processing_cost": 600,
"$.data.status": "active"
}
}
},
{
"id": "get_revisions",
"name": "변경 이력 조회",
"method": "GET",
"endpoint": "/pricing/{{create_price.price_id}}/revisions",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
}
},
{
"id": "get_cost",
"name": "원가 조회 (receipt > standard 폴백)",
"method": "GET",
"endpoint": "/pricing/cost",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"query": {
"item_type_code": "MATERIAL",
"item_id": 1,
"date": "2025-06-15"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.item_type_code": "MATERIAL",
"$.data.item_id": 1
}
}
},
{
"id": "by_items",
"name": "다중 품목 단가 조회",
"method": "POST",
"endpoint": "/pricing/by-items",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"items": [
{
"item_type_code": "MATERIAL",
"item_id": 1
}
],
"date": "2025-06-15"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
}
},
{
"id": "create_price_for_finalize",
"name": "확정 테스트용 단가 생성",
"method": "POST",
"endpoint": "/pricing",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"item_type_code": "PRODUCT",
"item_id": 1,
"purchase_price": 50000,
"sales_price": 70000,
"effective_from": "2025-01-01",
"status": "active"
},
"expect": {
"status": [201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber"
}
},
"extract": {
"finalize_price_id": "$.data.id"
}
},
{
"id": "finalize_price",
"name": "가격 확정 (불변 처리)",
"method": "POST",
"endpoint": "/pricing/{{create_price_for_finalize.finalize_price_id}}/finalize",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "finalized",
"$.data.is_final": true
}
}
},
{
"id": "delete_price",
"name": "단가 삭제 (soft delete)",
"method": "DELETE",
"endpoint": "/pricing/{{create_price.price_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "verify_deleted",
"name": "삭제된 단가 조회 시 404 확인",
"method": "GET",
"endpoint": "/pricing/{{create_price.price_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [404],
"jsonPath": {
"$.success": false
}
}
}
]
}

View File

@@ -1,227 +0,0 @@
{
"name": "Attendance API 근태관리 테스트",
"description": "근태 CRUD, 출퇴근 기록, 월간 통계 테스트",
"version": "1.0",
"config": {
"baseUrl": "",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}",
"test_date": "{{$date}}"
},
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{user_id}}",
"user_pwd": "{{user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.message": "로그인 성공",
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token",
"current_user_id": "$.user.id"
}
},
{
"id": "check_in",
"name": "출근 기록",
"method": "POST",
"endpoint": "/attendances/check-in",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"check_in": "09:00:00",
"gps_data": {
"latitude": 37.5665,
"longitude": 126.978,
"accuracy": 10
}
},
"expect": {
"status": [200, 201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber",
"$.data.status": "@isString"
}
},
"extract": {
"attendance_id": "$.data.id"
}
},
{
"id": "show_attendance",
"name": "근태 상세 조회",
"method": "GET",
"endpoint": "/attendances/{{check_in.attendance_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "{{check_in.attendance_id}}",
"$.data.base_date": "@isString"
}
}
},
{
"id": "check_out",
"name": "퇴근 기록",
"method": "POST",
"endpoint": "/attendances/check-out",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"check_out": "18:00:00",
"gps_data": {
"latitude": 37.5665,
"longitude": 126.978,
"accuracy": 15
}
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber"
}
}
},
{
"id": "list_attendances",
"name": "근태 목록 조회",
"method": "GET",
"endpoint": "/attendances",
"query": {
"page": 1,
"per_page": 10,
"date": "{{test_date}}"
},
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
},
{
"id": "monthly_stats",
"name": "월간 통계 조회",
"method": "GET",
"endpoint": "/attendances/monthly-stats",
"query": {
"year": 2025,
"month": 12
},
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "create_attendance",
"name": "근태 수동 등록 (관리자)",
"method": "POST",
"endpoint": "/attendances",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"user_id": "{{login.current_user_id}}",
"base_date": "2025-12-01",
"status": "onTime",
"json_details": {
"check_in": "09:00:00",
"check_out": "18:00:00",
"work_minutes": 480
},
"remarks": "Flow Tester 테스트 데이터"
},
"expect": {
"status": [200, 201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber"
}
},
"extract": {
"manual_attendance_id": "$.data.id"
}
},
{
"id": "update_attendance",
"name": "근태 수정",
"method": "PATCH",
"endpoint": "/attendances/{{create_attendance.manual_attendance_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"status": "late",
"remarks": "수정된 테스트 데이터"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.status": "late"
}
}
},
{
"id": "delete_manual_attendance",
"name": "수동 등록 근태 삭제",
"method": "DELETE",
"endpoint": "/attendances/{{create_attendance.manual_attendance_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "delete_checkin_attendance",
"name": "출퇴근 기록 삭제 (정리)",
"method": "DELETE",
"endpoint": "/attendances/{{check_in.attendance_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
}

View File

@@ -1,87 +0,0 @@
{
"name": "Department Tree API 테스트",
"description": "부서 트리 조회 테스트",
"version": "1.0",
"config": {
"baseUrl": "",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}"
},
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{user_id}}",
"user_pwd": "{{user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.message": "로그인 성공",
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token"
}
},
{
"id": "get_tree",
"name": "부서 트리 조회",
"method": "GET",
"endpoint": "/departments/tree",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
}
},
{
"id": "get_tree_with_users",
"name": "부서 트리 조회 (사용자 포함)",
"method": "GET",
"endpoint": "/departments/tree",
"query": {
"with_users": true
},
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
}
},
{
"id": "list_departments",
"name": "부서 목록 조회",
"method": "GET",
"endpoint": "/departments",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data": "@isArray"
}
}
}
]
}

View File

@@ -1,188 +0,0 @@
{
"name": "Employee API CRUD 테스트",
"description": "사원 관리 API 전체 CRUD 및 계정 생성 테스트",
"version": "1.0",
"config": {
"baseUrl": "",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"user_id": "{{$env.FLOW_TESTER_USER_ID}}",
"user_pwd": "{{$env.FLOW_TESTER_USER_PWD}}",
"test_email": "test.employee.{{$timestamp}}@example.com",
"test_name": "테스트사원{{$random:4}}"
},
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/login",
"body": {
"user_id": "{{user_id}}",
"user_pwd": "{{user_pwd}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.message": "로그인 성공",
"$.access_token": "@isString"
}
},
"extract": {
"token": "$.access_token",
"current_user_id": "$.user.id"
}
},
{
"id": "get_stats",
"name": "사원 통계 조회",
"method": "GET",
"endpoint": "/employees/stats",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.total": "@isNumber",
"$.data.active": "@isNumber",
"$.data.leave": "@isNumber",
"$.data.resigned": "@isNumber"
}
}
},
{
"id": "list_employees",
"name": "사원 목록 조회",
"method": "GET",
"endpoint": "/employees",
"query": {
"page": 1,
"per_page": 10
},
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.data": "@isArray"
}
}
},
{
"id": "create_employee",
"name": "사원 등록",
"method": "POST",
"endpoint": "/employees",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"name": "{{test_name}}",
"email": "{{test_email}}",
"phone": "010-1234-5678",
"employee_number": "EMP{{$random:6}}",
"employee_status": "active",
"position": "사원",
"hire_date": "{{$date}}",
"json_extra": {
"emergency_contact": "010-9999-8888",
"address": "서울시 강남구"
}
},
"expect": {
"status": [200, 201],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber",
"$.data.user.name": "{{test_name}}"
}
},
"extract": {
"employee_id": "$.data.id",
"user_id": "$.data.user_id"
}
},
{
"id": "show_employee",
"name": "사원 상세 조회",
"method": "GET",
"endpoint": "/employees/{{create_employee.employee_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "{{create_employee.employee_id}}",
"$.data.employee_status": "active"
}
}
},
{
"id": "update_employee",
"name": "사원 정보 수정",
"method": "PATCH",
"endpoint": "/employees/{{create_employee.employee_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"body": {
"position": "대리",
"employee_status": "active",
"json_extra": {
"emergency_contact": "010-1111-2222",
"address": "서울시 서초구",
"skills": ["Laravel", "React"]
}
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true,
"$.data.id": "@isNumber"
}
}
},
{
"id": "list_filtered",
"name": "사원 필터 조회 (재직자)",
"method": "GET",
"endpoint": "/employees",
"query": {
"status": "active",
"q": "{{test_name}}"
},
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
},
{
"id": "delete_employee",
"name": "사원 삭제",
"method": "DELETE",
"endpoint": "/employees/{{create_employee.employee_id}}",
"headers": {
"Authorization": "Bearer {{login.token}}"
},
"expect": {
"status": [200],
"jsonPath": {
"$.success": true
}
}
}
]
}

View File

@@ -1,926 +0,0 @@
{
"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"]
}
}
}