-
Notifications
You must be signed in to change notification settings - Fork 0
divisions
Domain: 수련부 및 수련반 관리
Base Path: /api/v1
| 메서드 | 경로 | 설명 | 권한 |
|---|---|---|---|
| GET | /sections |
수련부 목록 조회 | dojang.manageDivision |
| POST | /sections |
수련부 생성 | dojang.manageDivision |
| PATCH | /sections/:sectionId |
수련부 수정 | dojang.manageDivision |
| DELETE | /sections/:sectionId |
수련부 삭제 | dojang.manageDivision |
| PATCH | /sections/reorder |
수련부 순서 변경 | dojang.manageDivision |
| 메서드 | 경로 | 설명 | 권한 |
|---|---|---|---|
| GET | /divisions |
수련반 목록 조회 | dojang.manageDivision |
| GET | /divisions/:divisionId |
수련반 상세 조회 | dojang.manageDivision |
| POST | /divisions |
수련반 생성 | dojang.manageDivision |
| PATCH | /divisions/:divisionId |
수련반 수정 | dojang.manageDivision |
| DELETE | /divisions/:divisionId |
수련반 삭제 | dojang.manageDivision |
| PATCH | /divisions/reorder |
수련반 순서 변경 | dojang.manageDivision |
| 메서드 | 경로 | 설명 | 권한 |
|---|---|---|---|
| GET | /enrollments |
수련반 등록 원생 목록 조회 | dojang.manageDivision |
| POST | /enrollments |
원생 등록 | dojang.manageDivision |
| POST | /enrollments/bulk |
원생 일괄 등록 | dojang.manageDivision |
| DELETE | /enrollments/:studentId |
원생 등록 해제 | dojang.manageDivision |
Endpoint: GET /api/v1/sections
설명: 도장의 모든 수련부 목록을 조회합니다.
Request:
GET /api/v1/sections?dojangId=0J5FX8XNCSRPQ HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (200 OK):
{
"sections": [
{
"id": "0J5FX8XNCSRPQ",
"name": "유소년부",
"displayOrder": 1,
"divisionCount": 3
},
{
"id": "0J5FX8XNCSRPR",
"name": "청소년부",
"displayOrder": 2,
"divisionCount": 2
}
]
}Response Fields:
| 필드 | 타입 | 설명 |
|---|---|---|
| sections | array | 수련부 목록 (displayOrder 순) |
| sections[].id | string | 수련부 ID (13자리 TSID) |
| sections[].name | string | 수련부 이름 |
| sections[].displayOrder | integer | 표시 순서 |
| sections[].divisionCount | integer | 하위 수련반 수 |
Endpoint: POST /api/v1/sections
설명: 새로운 수련부를 생성합니다.
Request:
POST /api/v1/sections?dojangId=0J5FX8XNCSRPQ HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "유소년부"
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| name | string | ✅ | 수련부 이름 (1-50자) |
Response (200 OK):
{
"id": "0J5FX8XNCSRPQ",
"name": "유소년부",
"displayOrder": 1,
"divisionCount": 0
}Business Logic:
- JWT에서 tenant_id 추출 (dojangId와 동일 테넌트 검증)
- SECTION 레코드 생성
- displayOrder는 기존 최대값 + 1로 자동 설정
- 권한 검증: dojang.manageDivision
Endpoint: PATCH /api/v1/sections/:sectionId
설명: 수련부 정보를 수정합니다.
Request:
PATCH /api/v1/sections/0J5FX8XNCSRPQ?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "유소년부 (개편)"
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (200 OK):
{
"id": "0J5FX8XNCSRPQ",
"name": "유소년부 (개편)",
"displayOrder": 1,
"divisionCount": 3
}Endpoint: DELETE /api/v1/sections/:sectionId
설명: 수련부를 삭제합니다 (하위 수련반이 있으면 삭제 불가).
Request:
DELETE /api/v1/sections/0J5FX8XNCSRPQ?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (204 No Content)
Business Logic:
- 하위 수련반(DIVISION) 존재 여부 확인
- 하위 수련반이 있으면 400 Bad Request 응답
- 없으면 SECTION 레코드 삭제 (소프트 삭제)
Error Response (400 Bad Request):
{
"code": "HAS_CHILD_DIVISIONS",
"message": "하위 수련반이 존재하여 삭제할 수 없습니다",
"timestamp": "2026-01-08T12:00:00Z"
}Endpoint: PATCH /api/v1/sections/reorder
설명: 수련부들의 표시 순서를 변경합니다.
Request:
PATCH /api/v1/sections/reorder?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"sectionIds": ["0J5FX8XNCSRPR", "0J5FX8XNCSRPQ", "0J5FX8XNCSRPS"]
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| sectionIds | array | ✅ | 수련부 ID 목록 (순서대로 displayOrder 부여) |
Response (204 No Content)
Business Logic:
- 배열 순서대로 displayOrder 1, 2, 3... 부여
- 해당 도장의 수련부만 변경 가능
- 존재하지 않는 ID가 포함되면 400 Bad Request
Endpoint: GET /api/v1/divisions
설명: 특정 수련부의 수련반 목록을 조회합니다.
Request:
GET /api/v1/divisions?dojangId=0J5FX8XNCSRPT§ionId=0J5FX8XNCSRPQ HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
| sectionId | string | ✅ | 수련부 ID |
Response (200 OK):
{
"divisions": [
{
"id": "0J5FX8XNCSRPV",
"sectionId": "0J5FX8XNCSRPQ",
"sectionName": "유소년부",
"name": "유소년부 A반",
"displayOrder": 1,
"scheduleDays": ["MONDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "19:00",
"endTime": "20:00",
"studentCount": 15
}
]
}Response Fields:
| 필드 | 타입 | 설명 |
|---|---|---|
| divisions | array | 수련반 목록 (displayOrder 순) |
| divisions[].id | string | 수련반 ID (13자리 TSID) |
| divisions[].sectionId | string | 소속 수련부 ID |
| divisions[].sectionName | string | 소속 수련부 이름 |
| divisions[].name | string | 수련반 이름 |
| divisions[].displayOrder | integer | 표시 순서 |
| divisions[].scheduleDays | array | 수업 요일 배열 |
| divisions[].startTime | string | 시작 시각 (HH:mm) |
| divisions[].endTime | string | 종료 시각 (HH:mm) |
| divisions[].studentCount | integer | 등록된 원생 수 |
Endpoint: GET /api/v1/divisions/:divisionId
설명: 특정 수련반의 상세 정보를 조회합니다.
Request:
GET /api/v1/divisions/0J5FX8XNCSRPV?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (200 OK):
{
"id": "0J5FX8XNCSRPV",
"sectionId": "0J5FX8XNCSRPQ",
"sectionName": "유소년부",
"name": "유소년부 A반",
"displayOrder": 1,
"scheduleDays": ["MONDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "19:00",
"endTime": "20:00",
"studentCount": 15
}Note: 등록된 원생 목록은 별도 API(
GET /enrollments?divisionId=xxx)로 조회합니다.
Endpoint: POST /api/v1/divisions
설명: 새로운 수련반을 생성합니다.
Request:
POST /api/v1/divisions?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"sectionId": "0J5FX8XNCSRPQ",
"name": "유소년부 A반",
"scheduleDays": ["MONDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "19:00",
"endTime": "20:00"
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| sectionId | string | ✅ | 수련부 ID |
| name | string | ✅ | 수련반 이름 (1-50자) |
| scheduleDays | array | ❌ | 요일 배열 (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) |
| startTime | string | ❌ | 시작 시각 (HH:mm 형식) |
| endTime | string | ❌ | 종료 시각 (HH:mm 형식) |
Response (200 OK):
{
"id": "0J5FX8XNCSRPV",
"sectionId": "0J5FX8XNCSRPQ",
"sectionName": "유소년부",
"name": "유소년부 A반",
"displayOrder": 1,
"scheduleDays": ["MONDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "19:00",
"endTime": "20:00",
"studentCount": 0
}Business Logic:
- JWT에서 tenant_id 추출 (SECTION과 동일 테넌트 검증)
- DIVISION 레코드 생성
- scheduleDays는 Set로 저장
- displayOrder는 해당 수련부 내 최대값 + 1로 자동 설정
- 권한 검증: dojang.manageDivision
Endpoint: PATCH /api/v1/divisions/:divisionId
설명: 수련반 정보를 수정합니다.
Request:
PATCH /api/v1/divisions/0J5FX8XNCSRPV?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "유소년부 A반 (수정)",
"scheduleDays": ["MONDAY", "TUESDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "18:30",
"endTime": "19:30"
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (200 OK):
{
"id": "0J5FX8XNCSRPV",
"sectionId": "0J5FX8XNCSRPQ",
"sectionName": "유소년부",
"name": "유소년부 A반 (수정)",
"displayOrder": 1,
"scheduleDays": ["MONDAY", "TUESDAY", "WEDNESDAY", "FRIDAY"],
"startTime": "18:30",
"endTime": "19:30",
"studentCount": 15
}Endpoint: DELETE /api/v1/divisions/:divisionId
설명: 수련반을 삭제합니다 (등록된 원생이 있으면 삭제 불가).
Request:
DELETE /api/v1/divisions/0J5FX8XNCSRPV?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Response (204 No Content)
Business Logic:
- 등록된 원생(ENROLLMENT) 존재 여부 확인
- 등록된 원생이 있으면 400 Bad Request 응답
- 없으면 DIVISION 레코드 삭제 (소프트 삭제)
Error Response (400 Bad Request):
{
"code": "HAS_ENROLLED_STUDENTS",
"message": "등록된 원생이 존재하여 삭제할 수 없습니다",
"timestamp": "2026-01-08T12:00:00Z"
}Endpoint: PATCH /api/v1/divisions/reorder
설명: 특정 수련부 내 수련반들의 표시 순서를 변경합니다.
Request:
PATCH /api/v1/divisions/reorder?dojangId=0J5FX8XNCSRPT HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"sectionId": "0J5FX8XNCSRPQ",
"divisionIds": ["0J5FX8XNCSRPW", "0J5FX8XNCSRPV", "0J5FX8XNCSRPX"]
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| sectionId | string | ✅ | 수련부 ID |
| divisionIds | array | ✅ | 수련반 ID 목록 (순서대로 displayOrder 부여) |
Response (204 No Content)
Business Logic:
- 배열 순서대로 displayOrder 1, 2, 3... 부여
- 해당 수련부의 수련반만 변경 가능
- 다른 수련부의 수련반 ID가 포함되면 400 Bad Request
Endpoint: GET /api/v1/enrollments
설명: 특정 수련반에 등록된 원생 목록을 조회합니다.
Request:
GET /api/v1/enrollments?dojangId=0J5FX8XNCSRPT&divisionId=0J5FX8XNCSRPV HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
| divisionId | string | ✅ | 수련반 ID |
Response (200 OK):
{
"students": [
{
"studentId": "0J5FX8XNCSRPY",
"studentName": "홍길동",
"enrolledAt": "2025-01-20T10:00:00"
},
{
"studentId": "0J5FX8XNCSRPZ",
"studentName": "김철수",
"enrolledAt": "2025-01-22T14:30:00"
}
]
}Response Fields:
| 필드 | 타입 | 설명 |
|---|---|---|
| students | array | 등록된 원생 목록 |
| students[].studentId | string | 원생 ID |
| students[].studentName | string | 원생 이름 |
| students[].enrolledAt | datetime | 등록 일시 |
Endpoint: POST /api/v1/enrollments
설명: 수련반에 원생을 등록합니다.
Request:
POST /api/v1/enrollments?dojangId=0J5FX8XNCSRPT&divisionId=0J5FX8XNCSRPV HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"studentId": "0J5FX8XNCSRPY"
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
| divisionId | string | ✅ | 수련반 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| studentId | string | ✅ | 등록할 원생 ID |
Response (201 Created) - 응답 본문 없음
Business Logic:
- ENROLLMENT 레코드 생성
- 중복 등록 방지: (division_id, student_id) UNIQUE 제약
- 한 원생이 여러 수련반에 등록 가능
Endpoint: POST /api/v1/enrollments/bulk
설명: 수련반에 여러 원생을 일괄 등록합니다.
Request:
POST /api/v1/enrollments/bulk?dojangId=0J5FX8XNCSRPT&divisionId=0J5FX8XNCSRPV HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
"studentIds": ["0J5FX8XNCSRPY", "0J5FX8XNCSRPZ", "0J5FX8XNCSRP0"]
}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
| divisionId | string | ✅ | 수련반 ID |
Request Body:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| studentIds | array | ✅ | 등록할 원생 ID 목록 |
Response (200 OK):
{
"successCount": 2,
"failedCount": 1,
"failedStudentIds": ["0J5FX8XNCSRP0"]
}Response Fields:
| 필드 | 타입 | 설명 |
|---|---|---|
| successCount | integer | 등록 성공 수 |
| failedCount | integer | 등록 실패 수 |
| failedStudentIds | array | 실패한 원생 ID 목록 (이미 등록된 경우 등) |
Endpoint: DELETE /api/v1/enrollments/:studentId
설명: 수련반에서 원생 등록을 해제합니다.
Request:
DELETE /api/v1/enrollments/0J5FX8XNCSRPY?dojangId=0J5FX8XNCSRPT&divisionId=0J5FX8XNCSRPV HTTP/1.1
Host: api.example.com
Authorization: Bearer {access_token}Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| dojangId | string | ✅ | 도장 ID |
| divisionId | string | ✅ | 수련반 ID |
Response (204 No Content)
Business Logic:
- ENROLLMENT 레코드 삭제 (소프트 삭제)
- 과거 출석 이력은 유지됨
Last Updated: 2026-01-08