프론트엔드 개발자용 API 명세서
Base URL: https://api.beep.example.com (환경별 변경)
인증: Bearer Token (JWT)
Authorization: Bearer {accessToken}
- 인증 (Auth)
- 사용자 (User)
- 학생 일정 (Schedule)
- 실 (Room)
- 실 승인 (Room Approval)
- 체크포인트 (Checkpoint)
- 출석 타입 (Attendance Type)
- 출석 (Attendance)
- 실이동 (Shift)
- 장기결석 (Absence)
- 메모 (Memo)
- 알림 (Notification)
- 교내 행사 (Event)
- 큐빅 외박자 OpenAPI
| 항목 | 내용 |
|---|---|
| URL | POST /dauth/login |
| 설명 | DAuth OAuth 인증 코드로 로그인 |
| 인증 | 불필요 |
Request Body
{
"code": "dauth_authorization_code"
}Response 200 OK
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}| 항목 | 내용 |
|---|---|
| URL | POST /auth/refresh |
| 설명 | Refresh Token으로 새로운 토큰 발급 |
| 인증 | 불필요 |
Request Body
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Response 200 OK
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}| 항목 | 내용 |
|---|---|
| URL | GET /users/my |
| 설명 | 현재 로그인한 사용자 정보 조회 |
| 인증 | 필요 |
Response 200 OK
{
"id": 1,
"email": "student@dsm.hs.kr",
"username": "홍길동",
"role": "STUDENT",
"profileImage": "https://...",
"studentInfo": {
"grade": 2,
"classNumber": 3,
"num": 15
},
"currentStatus": {
"id": 1,
"name": "동아리"
}
}| 항목 | 내용 |
|---|---|
| URL | DELETE /users/{userId} |
| 설명 | 사용자 계정 삭제 (Soft Delete) |
| 인증 | 필요 (ADMIN) |
| Path Param | userId: 삭제할 사용자 ID |
Response 200 OK
| 항목 | 내용 |
|---|---|
| URL | GET /students |
| 설명 | 학생 목록 조회 (필터/페이징) |
| 인증 | 필요 (TEACHER) |
Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
grade |
Integer | X | 학년 (1, 2, 3) |
classNumber |
Integer | X | 반 (1, 2, 3, 4) |
keyword |
String | X | 이름 검색 |
page |
Integer | X | 페이지 번호 (기본: 0) |
size |
Integer | X | 페이지 크기 (기본: 20) |
Response 200 OK
{
"content": [
{
"id": 1,
"email": "student@dsm.hs.kr",
"username": "홍길동",
"studentInfo": {
"grade": 2,
"classNumber": 3,
"num": 15
}
}
],
"totalElements": 100,
"totalPages": 5,
"size": 20,
"number": 0
}| URL | Method | 설명 |
|---|---|---|
/limited-users |
POST |
제한 사용자 등록 |
/limited-users |
GET |
제한 사용자 목록 |
/limited-users/{id} |
PATCH |
제한 사용자 수정 |
/limited-users/{id} |
DELETE |
제한 사용자 삭제 |
POST Request Body
{
"email": "blocked@dsm.hs.kr"
}GET Response 200 OK
[
{
"id": 1,
"email": "blocked@dsm.hs.kr"
}
]| URL | Method | 설명 | 비고 |
|---|---|---|---|
/schedules |
POST |
학생 일정 생성 | 교사용 |
/schedules |
GET |
특정 학생 일정 조회 | ?userId= 필수 |
/schedules/my |
POST |
내 일정 생성 | 학생용 |
/schedules/my |
GET |
내 일정 조회 | 학생용 |
/schedules/{scheduleId} |
PATCH |
일정 수정 | |
/schedules/{scheduleId} |
DELETE |
일정 삭제 |
POST /schedules Request Body
{
"userId": 1,
"dayOfWeek": "MONDAY",
"checkpointId": 1,
"typeId": 1,
"roomId": 1
}POST /schedules/my Request Body
{
"dayOfWeek": "MONDAY",
"checkpointId": 1,
"typeId": 1,
"roomId": 1
}dayOfWeek 값: MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
[
{
"id": 1,
"dayOfWeek": "MONDAY",
"checkpoint": {
"id": 1,
"name": "1차 자습"
},
"type": {
"id": 1,
"name": "동아리"
},
"room": {
"id": 1,
"name": "동아리실 1"
}
}
]| URL | Method | 설명 |
|---|---|---|
/rooms |
POST |
실 생성 |
/rooms |
GET |
실 목록 조회 |
/rooms/{roomId} |
GET |
실 상세 조회 |
/rooms/{roomId} |
PATCH |
실 수정 |
/rooms/{roomId} |
DELETE |
실 삭제 |
Request Body
{
"name": "동아리실 1",
"grade": 2,
"classNumber": 3,
"floor": 4
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
name |
String | O | 실 이름 (최대 100자) |
grade |
Integer | X | 학년 |
classNumber |
Integer | X | 반 |
floor |
Integer | X | 층 |
{
"id": 1,
"name": "동아리실 1",
"grade": 2,
"classNumber": 3,
"floor": 4,
"currentStudentCount": 10
}GET /rooms, GET /rooms/{roomId}의 응답 name은 서울 시간 기준 오늘 날짜와 학년별 현재/가까운 체크포인트의 적용 타입으로 결정합니다.
적용 타입은 날짜별 재정렬 변경값(attendance_sort_modes)이 있으면 해당 타입을 사용하고, 없을 때만 요일별 기본값(attendance_sort_mode_defaults)을 사용합니다.
| 재정렬 변경값 | 기본값 | 응답 name |
|---|---|---|
| 동아리 | 무관 | 동아리명(clubName) |
| 동아리 외 타입 | 무관 | 실제 실 이름 |
| 없음 | 동아리 | 동아리명(clubName) |
| 없음 | 동아리 외 타입 또는 미등록 | 실제 실 이름 |
동아리명이 없거나 공백이면 실제 실 이름을 반환합니다. 학년이 지정된 실은 해당 학년의 적용 타입만 확인하고, 학년 없는 공용 실은 1~3학년 중 적용 타입이 동아리인 학년이 있으면 동아리명을 반환합니다.
표시 이름 판단에는 학생별 스케줄이나 활동실 등록 현황을 사용하지 않습니다. 응답의 표시 이름만 변경하며 DB에 저장된 실 이름과 clubName은 그대로 유지합니다.
GET /rooms, GET /rooms/{roomId}의 currentStudentCount는 해당 실·요일·현재 체크포인트에 스케줄된 학생 중 출석 기록이 있는 학생 수입니다.
- 출석 상태가
외박또는외출인 학생은 제외합니다. 교실자습,동아리,나르샤,방과후,실이동,교내 행사등 다른 출석 상태는 포함합니다.- 출석 기록이 없는 미출석 학생은 제외합니다.
- 현재 체크포인트가 없거나 해당 스케줄 학생이 없으면
0을 반환합니다.
원 스케줄 기준으로 집계하며, 실이동으로 이 실에 들어온 학생은 별도로 더하지 않습니다.
교사가 특정 체크포인트에 실을 점검 완료했음을 표시
| URL | Method | 설명 |
|---|---|---|
/rooms/{roomId}/approvals |
POST |
실 승인 생성 |
/rooms/{roomId}/approvals |
GET |
특정 실 승인 상태 조회 |
/rooms/{roomId}/approvals |
DELETE |
실 승인 삭제 |
/approvals |
GET |
전체 승인 목록 조회 |
GET /approvals Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
approved |
Boolean | X | true: 승인됨, false: 미승인, 없음: 전체 |
Response 200 OK
[
{
"room": {
"id": 1,
"name": "동아리실 1"
},
"approved": true,
"approvedTeacher": {
"id": 1,
"username": "김선생"
},
"approvedAt": "2024-01-15T19:30:00"
}
]출석 시간대 (예: 1차 자습, 2차 자습)
| URL | Method | 설명 |
|---|---|---|
/checkpoints |
POST |
체크포인트 생성 |
/checkpoints |
GET |
체크포인트 목록 조회 |
/checkpoints/{checkpointId} |
GET |
체크포인트 상세 조회 |
/checkpoints/{checkpointId} |
PATCH |
체크포인트 수정 |
/checkpoints/{checkpointId} |
DELETE |
체크포인트 삭제 |
Request Body
{
"name": "1차 자습",
"startAt": "19:00",
"endAt": "21:00",
"attendanceStartAt": "18:50",
"attendanceEndAt": "19:10"
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
name |
String | O | 체크포인트 이름 (최대 50자) |
startAt |
LocalTime | O | 시작 시간 (HH:mm) |
endAt |
LocalTime | O | 종료 시간 (HH:mm) |
attendanceStartAt |
LocalTime | O | 출석 가능 시작 시간 |
attendanceEndAt |
LocalTime | O | 출석 가능 종료 시간 |
{
"id": 1,
"name": "1차 자습",
"startAt": "19:00",
"endAt": "21:00",
"attendanceStartAt": "18:50",
"attendanceEndAt": "19:10"
}출석 상태 종류 (예: 동아리, 교실자습, 외박)
| URL | Method | 설명 |
|---|---|---|
/types |
POST |
출석 타입 생성 |
/types |
GET |
출석 타입 목록 조회 |
/types/{id} |
GET |
출석 타입 상세 조회 |
/types/{id} |
PUT |
출석 타입 수정 |
/types/{id} |
DELETE |
출석 타입 삭제 |
Request Body
{
"name": "동아리"
}[
{ "id": 1, "name": "동아리" },
{ "id": 2, "name": "교실자습" },
{ "id": 3, "name": "외박" },
{ "id": 4, "name": "미출석" }
]시스템 예약 타입
미출석: 출석하지 않은 기본 상태외박: 장기결석 기본 타입
| URL | Method | 설명 | 대상 |
|---|---|---|---|
/attendances |
POST |
출석하기 | 학생 |
/attendances/cancel |
PATCH |
출석 취소 | 학생 |
/attendances |
GET |
출석 현황 조회 | 교사 |
/attendances/status |
PATCH |
출석 상태 변경 | 교사 |
/attendances/statuses |
PATCH |
선택 학생 출석 상태 일괄 변경 | 교사 |
/attendances/histories |
GET |
출석 히스토리 파일 목록 | 교사 |
/attendances/histories/download |
GET |
출석 히스토리 다운로드 | 교사 |
/attendance-sort-modes |
GET |
학년별 재정렬 변경값 및 기본값 조회 | 교사 |
/attendance-sort-modes |
PATCH |
학년별 재정렬 변경 또는 기본 스케줄 복원 | 교사 |
POST /attendances Request Body
{
"roomId": 1,
"typeId": 1
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
roomId |
Long | O | 출석할 실 ID |
typeId |
Long | O | 출석 타입 ID |
주의사항
- 출석 가능 시간(
attendanceStartAt~attendanceEndAt) 내에만 출석 가능 - 이미 출석한 경우
ALREADY_ATTENDED에러 - 오늘 날짜·출석 체크포인트·학생 학년에 해당하는 재정렬 변경값이 없으면, 출석한 타입과 실로 학생의 요일별 스케줄을 생성하거나 갱신합니다.
- 해당 조건의 재정렬 변경값이 있으면 학생 스케줄은 생성·수정하지 않고 당일 출석 기록만 저장합니다. 기본값과 동일한 타입을 선택한 변경값도 이 정책을 따릅니다.
- QR 출석(
POST /attendances/help/scan)에도 동일한 스케줄 갱신 정책을 적용합니다.
GET /attendances Query Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
roomId |
Long | X | - | 실 필터 |
statusId |
Long | X | - | 출석 타입 필터 |
grade |
Integer | X | - | 학년 필터 |
classNumber |
Integer | X | - | 반 필터 |
isCurrentCheckpoint |
Boolean | X | true |
현재 체크포인트만 조회 |
page |
Integer | X | 0 | 페이지 번호 |
size |
Integer | X | 20 | 페이지 크기 |
Response 200 OK
{
"content": [
{
"userId": 1,
"studentId": "2315",
"username": "홍길동",
"statuses": [
{
"checkpoint": { "id": 1, "name": "1차 자습" },
"status": { "id": 1, "name": "동아리" }
},
{
"checkpoint": { "id": 2, "name": "2차 자습" },
"status": null
}
]
}
],
"totalElements": 100,
"totalPages": 5
}PATCH /attendances/status Request Body
{
"userId": 1,
"statusId": 2,
"date": "2024-01-15",
"checkpointId": 1
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
userId |
Long | O | 학생 ID |
statusId |
Long | O | 변경할 출석 타입 ID |
date |
LocalDate | X | 날짜 (기본: 오늘) |
checkpointId |
Long | X | 체크포인트 ID (기본: 현재) |
PATCH /attendances/statuses Request Body
{
"userIds": [1, 2, 3],
"typeId": 2,
"date": "2026-09-15",
"checkpointId": 1
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
userIds |
List<Long> | O | 변경할 학생 ID 목록 |
typeId |
Long | O | 공통으로 적용할 출석 타입 ID |
date |
LocalDate | X | 날짜 (기본: 오늘) |
checkpointId |
Long | X | 체크포인트 ID (기본: 현재) |
타입이 다른 학생 그룹은 typeId별로 요청을 나누어 호출합니다. 중복된 학생 ID는 한 번만 처리됩니다.
Response 204 No Content
GET /attendances/histories/download Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
date |
String | O | 날짜 (파일명 형식) |
Response 200 OK
{
"url": "https://s3.amazonaws.com/..."
}GET /attendance-sort-modes
서울 시간 기준 오늘 요일과 학년별 현재/가까운 체크포인트로 조회합니다. 별도 쿼리 파라미터는 없습니다.
Response 200 OK
다음은 수요일 10~11교시 응답 예시입니다. 체크포인트와 타입 ID는 환경별 실제 값을 사용합니다.
{
"date": "2026-10-07",
"modes": [
{
"grade": 1,
"checkpoint": { "id": 2, "name": "10~11교시" },
"type": null,
"defaultType": { "id": 1, "name": "동아리" }
},
{
"grade": 2,
"checkpoint": { "id": 2, "name": "10~11교시" },
"type": null,
"defaultType": { "id": 1, "name": "동아리" }
},
{
"grade": 3,
"checkpoint": { "id": 2, "name": "10~11교시" },
"type": null,
"defaultType": { "id": 1, "name": "동아리" }
}
]
}| 필드 | 설명 |
|---|---|
date |
조회 기준 날짜 |
modes[].grade |
학년 (1~3) |
modes[].checkpoint |
해당 학년의 현재/가까운 체크포인트 |
modes[].type |
날짜별 재정렬 변경값. 변경값이 없으면 null |
modes[].defaultType |
요일·체크포인트·학년별 기본 타입. 미등록이거나 삭제된 타입 또는 지원하지 않는 타입이면 null |
화면 선택값은 type ?? defaultType으로 표시하고, 둘 다 없으면 기본 스케줄로 표시합니다. 초기 선택값을 표시할 때 PATCH를 호출하지 않습니다. 실제 학생 배치는 변경값이 없을 때 학생별 스케줄을 사용합니다.
기본값은 attendance_sort_mode_defaults에 별도로 등록하고 (day_of_week, checkpoint_id, grade) 조합은 중복될 수 없습니다. 서버 기동·재시작 시 기본값을 자동 생성하거나 변경하지 않습니다. 기본값 관리 API는 제공하지 않습니다.
PATCH /attendance-sort-modes Request Body
{
"grade": 1,
"typeId": 2
}학년은 1~3이며, 선택 가능한 타입은 동아리·교실자습·나르샤·방과후입니다. typeId: null을 보내면 해당 학년의 오늘 현재/가까운 체크포인트 변경값을 삭제하여 기본 스케줄로 복원합니다. 이 경우 학생 출석에 따른 스케줄 갱신도 다시 허용됩니다.
Response 200 OK: GET과 동일한 형식으로 변경 후 학년별 변경값과 기본값을 반환합니다.
학생이 다른 실로 이동 신청
| URL | Method | 설명 | 대상 |
|---|---|---|---|
/shifts |
POST |
실이동 신청 | 학생 |
/shifts/my |
GET |
내 실이동 목록 | 학생 |
/shifts/{shiftId} |
PATCH |
실이동 수정 | 학생 |
/shifts/{shiftId} |
DELETE |
실이동 삭제 | 학생 |
/shifts |
GET |
전체 실이동 목록 | 교사 |
/shifts/{shiftId}/status |
PATCH |
실이동 승인/거절 | 교사 |
POST /shifts Request Body
{
"roomId": 1,
"reason": "동아리 활동 참여",
"checkpointId": 1,
"date": "2024-01-15"
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
roomId |
Long | O | 이동할 실 ID |
reason |
String | O | 사유 (최대 300자) |
checkpointId |
Long | O | 체크포인트 ID |
date |
LocalDate | O | 날짜 (오늘 이후) |
[
{
"id": 1,
"user": {
"id": 1,
"username": "홍길동",
"studentInfo": {
"grade": 2,
"classNumber": 3,
"num": 15
}
},
"room": {
"id": 1,
"name": "동아리실 1"
},
"checkpoint": {
"id": 1,
"name": "1차 자습"
},
"reason": "동아리 활동 참여",
"status": "WAITING",
"date": "2024-01-15"
}
]status 값
WAITING: 대기중APPROVED: 승인됨REJECTED: 거절됨
PATCH /shifts/{shiftId}/status Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
status |
String | O | APPROVED, REJECTED, WAITING |
외박, 병결 등 장기 결석 관리
| URL | Method | 설명 | 응답 |
|---|---|---|---|
/absences |
POST |
장기결석 생성 | 200 |
/absences |
GET |
장기결석 목록 조회 | 200 |
/absences/{absenceId} |
PATCH |
장기결석 수정 | 200 |
/absences/{absenceId} |
DELETE |
장기결석 삭제 | 204 |
POST /absences Request Body
{
"userIds": [1, 2, 3],
"startDate": "2024-01-15",
"endDate": "2024-01-17",
"reason": "가정체험학습",
"checkpoints": [
{ "checkpointId": 1, "typeId": 5 },
{ "checkpointId": 2, "typeId": 6 },
{ "checkpointId": 3 }
]
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
userIds |
Long[] | O | 대상 학생 ID 목록 |
startDate |
LocalDate | O | 시작일 (오늘 이후) |
endDate |
LocalDate | O | 종료일 (시작일 이후) |
reason |
String | O | 사유 (최대 500자) |
checkpoints |
CheckpointSetting[] | X | 체크포인트별 타입 설정 (미지정 시 전체 체크포인트) |
CheckpointSetting
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
checkpointId |
Long | O | 체크포인트 ID |
typeId |
Long | X | 해당 체크포인트의 출석 타입 (미지정 시 기본 결석 타입) |
Response 200 OK
{
"absenceId": 1,
"skippedUserIds": [3]
}| 필드 | 타입 | 설명 |
|---|---|---|
absenceId |
Long | 생성된 결석 ID (모두 스킵된 경우 null) |
skippedUserIds |
Long[] | 중복으로 제외된 학생 ID 목록 |
PATCH /absences/{absenceId} Request Body
생성과 동일한 형식
Response 200 OK
{
"absenceId": 1,
"skippedUserIds": []
}{
"content": [
{
"absenceId": 1,
"isGrouped": false,
"targetStudents": [
{
"name": "홍길동",
"info": { "grade": 2, "classNumber": 3, "num": 15 }
}
],
"startDate": "2024-01-15",
"endDate": "2024-01-17",
"reason": "가정체험학습",
"checkpoints": [
{
"checkpoint": { "id": 1, "name": "1차 자습" },
"type": { "id": 5, "name": "외출" }
},
{
"checkpoint": { "id": 2, "name": "2차 자습" },
"type": { "id": 6, "name": "조퇴" }
}
]
}
],
"totalElements": 10,
"totalPages": 1
}학년별 교사 메모. 학년당 하나만 존재한다.
| URL | Method | 설명 | 권한 |
|---|---|---|---|
/memos/{grade} |
POST |
메모 생성 (이미 있으면 내용 갱신) | TEACHER |
/memos/{grade} |
GET |
메모 조회 | TEACHER |
/memos/{grade} |
PATCH |
메모 수정 | TEACHER |
grade는 1~3.
content는 두 부분이 합쳐진 값이다.
내일 시험이니 조용히 시키기 ← 수기 영역
← 빈 줄로 구분
8월 26일 ← 자동 영역 시작
8~9교시 체육대회 (3명 참여)
1101 김철수 / 1102 이영희 / 1103 박민수
- 수기 영역은 교사가 쓴 내용이며 행사 변경에 영향받지 않는다. 조회 시 위쪽에 온다.
- 자동 영역은 교내 행사 등록·수정·삭제 때마다 서버가 통째로 다시 만든다. 여기를 직접 고쳐 보내도 다음 행사 변경 때 덮어써진다. 매일 21:50(Asia/Seoul)에 서버가 비운다. 수기 영역은 이 스케줄의 대상이 아니다.
PATCH로 보낸 전체 텍스트에서 서버가 뒤쪽 자동 영역을 떼어내고 나머지를 수기 영역으로 저장한다. 조회로 받은content를 그대로 편집해서 보내면 된다.
Request Body (POST는 content, PATCH는 newContent)
{
"content": "내일 시험이니 조용히 시키기"
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
content / newContent |
String | O | 메모 내용 (최대 30000자) |
{
"grade": 1,
"content": "내일 시험이니 조용히 시키기\n\n8월 26일\n8~9교시 체육대회 (3명 참여)\n1101 김철수",
"isRead": true
}조회하면 isRead가 true로 바뀐다. 수정하면 다시 false가 된다.
| 항목 | 내용 |
|---|---|
| URL | POST /fcm |
| 설명 | 푸시 알림용 FCM 토큰 저장 |
| 인증 | 필요 |
Request Body
{
"token": "fcm_device_token...",
"device": "android"
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
token |
String | O | FCM 디바이스 토큰 |
device |
String | O | 디바이스 종류 (android, ios, web) |
| 항목 | 내용 |
|---|---|
| URL | GET /fcm |
| 설명 | 전체 사용자에게 테스트 푸시 알림 발송 |
| 인증 | 필요 |
Response 200 OK (응답 본문 없음)
교내 행사로 자습에서 빠지는 학생을 지정한다. 등록하면 해당 학생 × 교시의 출석이
교내 행사타입으로 미리 생성되고, 참여 학년의 메모 자동 영역이 갱신된다.
권한: 전 엔드포인트 TEACHER
| URL | Method | 설명 |
|---|---|---|
/events |
POST |
행사 등록 |
/events?date= |
GET |
날짜별 행사 목록 |
/events/{eventId} |
GET |
행사 상세 |
/events/{eventId} |
PATCH |
행사 수정 |
/events/{eventId} |
DELETE |
행사 삭제 |
Request Body (POST /events, PATCH /events/{eventId} 동일)
{
"name": "체육대회",
"date": "2026-08-26",
"checkpointIds": [1, 2],
"userIds": [11, 12, 13]
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
name |
String | O | 행사명 (최대 100자) |
date |
String | O | 행사 날짜 yyyy-MM-dd |
checkpointIds |
Long[] | O | 교시 ID 목록 (1개 이상). GET /checkpoints에서 조회 |
userIds |
Long[] | O | 참여 학생 ID 목록 (1개 이상). GET /students에서 조회 |
담당 교사는 요청 토큰에서 자동으로 채워진다. 요청 본문에 넣지 않는다.
수정은 기존 출석·참여자·교시를 모두 지우고 새 내용으로 다시 만든다. 이번 수정으로 빠지는 학년의 메모도 함께 갱신된다.
GET /events?date=2026-08-26 — date를 생략하면 오늘 날짜로 조회한다.
[
{
"id": 3,
"name": "체육대회",
"date": "2026-08-26",
"checkpointNames": ["8~9교시", "10~11교시"],
"studentCount": 10,
"createdByName": "천준범"
}
]checkpointNames는 교시 시작 시각 순으로 정렬된다.
GET /events/{eventId} — 수정 화면을 채울 때 쓴다.
{
"id": 3,
"name": "체육대회",
"date": "2026-08-26",
"checkpoints": [
{ "id": 1, "name": "8~9교시" },
{ "id": 2, "name": "10~11교시" }
],
"students": [
{ "userId": 11, "studentId": "1101", "name": "김철수" },
{ "userId": 21, "studentId": "2101", "name": "이영희" }
],
"createdByName": "천준범"
}students는 학번 순으로 정렬된다.
| 코드 | 상태 | 설명 |
|---|---|---|
EVENT_NOT_FOUND |
404 | 행사를 찾을 수 없음 |
EMPTY_CHECKPOINTS |
400 | 교시를 하나도 선택하지 않음 |
EMPTY_USERS |
400 | 학생을 하나도 선택하지 않음 |
USER_NOT_FOUND |
404 | 없는 학생 ID가 섞임 |
CHECKPOINT_NOT_FOUND |
404 | 없는 교시 ID가 섞임 |
- 참여 학생의 출석 상태가 해당 교시에
교내 행사로 표시된다 - 출석 독촉 푸시 알림 대상에서 제외된다
- 해당 실의 스케줄에 배정되고 해당 교시에 출석 기록이 있으면
currentStudentCount에 포함된다 (외박·외출만 제외) - 교사가 상태를
미출석으로 되돌려도 행사 출석 기록은 삭제되지 않는다 (행사 목록과 어긋나지 않게 하기 위함)
입력한 날짜에 외박 중인 학생 명단을 큐빅에 제공한다. 일반 사용자 JWT 대신 큐빅 전용 API 키를 사용한다.
| 항목 | 내용 |
|---|---|
| Method | GET |
| URL | /out-sleeping/openapi/search |
| 인증 | X-Qvik-Api-Key 헤더 |
Request Header
X-Qvik-Api-Key: {qvikApiKey}Query Parameters
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
date |
String | O | 검색할 날짜 (yyyy-MM-dd) |
다음 조건 중 하나를 만족하는 학생을 포함한다.
- 조회일이 외박자 관리에 등록된
외박기간에 포함되는 학생 - 조회일의 체크포인트 중 하나라도 출석 상태가
외박인 학생
같은 학생이 두 조건이나 여러 체크포인트에 중복되면 한 번만 반환한다. 결과는 학년, 반, 번호, 이름 순으로 정렬된다.
Response 200 OK
{
"content": [
{
"publicId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"reason": "가정 사유",
"student": {
"name": "홍길동",
"grade": 2,
"room": 3,
"number": 15
},
"startAt": "2026-05-19",
"endAt": "2026-05-21"
}
]
}| 필드 | 타입 | 설명 |
|---|---|---|
content |
Object[] | 외박 학생 목록. 결과가 없으면 빈 배열 |
publicId |
String? | 학생 DAuth 공개 식별자. 기존 데이터에 없으면 null |
reason |
String | 외박 사유 |
student.name |
String | 학생 이름 |
student.grade |
Int | 학년 |
student.room |
Int | 반 |
student.number |
Int | 번호 |
startAt |
String | 외박 시작 날짜 (yyyy-MM-dd) |
endAt |
String | 외박 종료 날짜 (yyyy-MM-dd) |
외박자 관리에 등록된 학생은 absence, absence_users, users를 연결해 학생의 publicId와 등록된 사유·기간을 반환한다. 출석 타입만 외박으로 변경한 학생은 reason을 일반 외박으로, startAt과 endAt을 조회한 날짜로 반환한다. 두 조건에 모두 해당하면 외박자 관리의 등록 정보를 우선하고 한 건만 반환한다.
| 코드 | 상태 | 설명 |
|---|---|---|
DATE_REQUIRED |
400 | date 파라미터 누락 |
METHOD_ARGUMENT_TYPE_MISMATCH |
400 | 날짜 형식 오류 |
INVALID_QVIK_API_KEY |
401 | API 키 누락 또는 불일치 |
운영 환경에는 QVIK_API_KEY 환경변수를 반드시 설정해야 한다. 누락하거나 공백으로 설정하면 애플리케이션이 시작되지 않는다.
{
"status": 400,
"code": "VALIDATION_ERROR",
"message": "잘못된 요청입니다."
}| 코드 | 상태 | 설명 |
|---|---|---|
USER_NOT_FOUND |
404 | 사용자를 찾을 수 없음 |
ROOM_NOT_FOUND |
404 | 실을 찾을 수 없음 |
CHECKPOINT_NOT_FOUND |
404 | 체크포인트를 찾을 수 없음 |
ATTENDANCE_NOT_FOUND |
404 | 출석 기록을 찾을 수 없음 |
SHIFT_NOT_FOUND |
404 | 실이동 신청을 찾을 수 없음 |
ABSENCE_NOT_FOUND |
404 | 장기결석을 찾을 수 없음 |
ALREADY_ATTENDED |
400 | 이미 출석 처리됨 |
TYPE_MISMATCH |
400 | 일정과 출석 타입 불일치 |
ROOM_MISMATCH |
400 | 일정과 실 불일치 |
CHECKPOINT_TIME_OVERLAP |
409 | 체크포인트 시간 겹침 |
ROOM_ALREADY_EXISTS |
409 | 이미 존재하는 실 이름 |
SHIFT_ALREADY_EXISTS |
409 | 중복 실이동 신청 |
ALREADY_APPROVED |
409 | 이미 승인됨 |
PASSED_TIME |
400 | 이미 지난 시간 |
INVALID_DATE_RANGE |
400 | 잘못된 날짜 범위 |
EXPIRED_TOKEN |
401 | 만료된 토큰 |
INVALID_TOKEN |
401 | 잘못된 토큰 |
| 값 | 설명 |
|---|---|
STUDENT |
학생 |
TEACHER |
교사 |
ADMIN |
관리자 |
| 값 | 설명 |
|---|---|
MONDAY |
월요일 |
TUESDAY |
화요일 |
WEDNESDAY |
수요일 |
THURSDAY |
목요일 |
FRIDAY |
금요일 |
SATURDAY |
토요일 |
SUNDAY |
일요일 |
| 값 | 설명 |
|---|---|
WAITING |
대기중 |
APPROVED |
승인됨 |
REJECTED |
거절됨 |