1. API 목록

2. 투표 기간 관련

2.1. GET: 투표 기간 조회

HTTP Request
GET /contests/1/vote HTTP/1.1
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 82

{
  "voteStartAt" : "2026-01-01T00:00:00",
  "voteEndAt" : "2026-01-02T00:00:00"
}
Table 1. /contests/{contestId}/vote
Parameter Description

contestId

대회 ID

Table 2. Response Fields
Path Type Description

voteStartAt

String

투표 시작일 (ISO-8601)

voteEndAt

String

투표 종료일 (ISO-8601)

2.2. PUT: 투표 기간 수정

HTTP Request
PUT /contests/1/vote HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 82
Host: localhost:8080

{
  "voteStartAt" : "2026-02-01T00:00:00",
  "voteEndAt" : "2026-02-10T00:00:00"
}
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Table 3. /contests/{contestId}/vote
Parameter Description

contestId

대회 ID

Table 4. Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 5. Request Fields
Path Type Description

voteStartAt

String

투표 시작일 (ISO-8601)

voteEndAt

String

투표 종료일 (ISO-8601)

3. 최대 투표 개수 관리

3.1. PATCH: 최대 투표 개수 설정

Table 6. /contests/{contestId}/votes
Parameter Description

contestId

대회의 고유 ID

Table 7. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
PATCH /contests/1/votes HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 25
Host: localhost:8080

{
  "maxVotesLimit" : 2
}
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Table 8. Request Fields
Path Type Description

maxVotesLimit

Number

최대 투표 개수

3.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
PATCH /contests/999/votes HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 25
Host: localhost:8080

{
  "maxVotesLimit" : 2
}
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}
❌ Case 2: 투표 진행 중
PATCH /contests/1/votes HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 25
Host: localhost:8080

{
  "maxVotesLimit" : 2
}
HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 94

{
  "message" : "현재 투표 기간이므로 해당 작업을 수행할 수 없습니다."
}

3.2. GET: 최대 투표 개수 조회

Table 9. /contests/{contestId}/votes
Parameter Description

contestId

대회의 고유 ID

Table 10. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
GET /contests/1/votes HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 25

{
  "maxVotesLimit" : 2
}
Table 11. Response Body’s Fields
Path Type Description

maxVotesLimit

Number

최대 투표 개수

3.2.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
GET /contests/999/votes HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

4. 대회 배너 이미지 관리

4.1. GET: 대회 배너 이미지 조회

Table 12. /contests/{contestId}/image/banner
Parameter Description

contestId

대회 ID

HTTP Request
GET /contests/1/image/banner HTTP/1.1
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: image/png;charset=UTF-8
Accept-Ranges: bytes
Content-Length: 18

test-image-content

4.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
GET /contests/999/image/banner HTTP/1.1
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}
❌ Case 2: 등록되지 않은 이미지
GET /contests/1/image/banner HTTP/1.1
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 71

{
  "message" : "아이디와 일치하는 이미지가 없습니다"
}
❌ Case 3: 변환 중인 이미지
GET /contests/1/image/banner HTTP/1.1
Host: localhost:8080
HTTP/1.1 202 Accepted
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 49

{
  "message" : "이미지 변환중 입니다"
}

4.2. POST: 대회 배너 이미지 등록

Table 13. /contests/{contestId}/image/banner
Parameter Description

contestId

대회 ID

Table 14. Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 15. Request Parts
Part Description

image

등록할 배너 이미지 (모든 이미지 형식 지원)

HTTP Request
POST /contests/1/image/banner HTTP/1.1
Content-Type: multipart/form-data;charset=UTF-8; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
Authorization: Bearer admin.access.token
Host: localhost:8080

--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
Content-Disposition: form-data; name=image; filename=banner.png
Content-Type: image/png

test-image-content
--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
HTTP Response
HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

4.3. DELETE: 대회 배너 이미지 삭제

Table 16. /contests/{contestId}/image/banner
Parameter Description

contestId

대회 ID

Table 17. Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
DELETE /contests/1/image/banner HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

5. 정렬 관리

5.1. PUT: 대회 정렬 설정 변경

Table 18. /contests/{contestId}/sort
Parameter Description

contestId

대회 ID

Table 19. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
PUT /contests/1/sort HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 20
Host: localhost:8080

{
  "mode" : "ASC"
}
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Table 20. Request Fields
Path Type Description

mode

String

수정할 대회 정렬 모드

5.2. GET: 대회 정렬 방식 조회

Table 21. /contests/{contestId}/sort
Parameter Description

contestId

대회 ID

Table 22. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
GET /contests/1/sort HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 27

{
  "currentMode" : "ASC"
}
Table 23. Response Fields
Path Type Description

currentMode

String

현재 적용되어 있는 모드 정보

5.3. PUT: 대회 수동 정렬 순서 저장

Table 24. /contests/{contestId}/sort/custom
Parameter Description

contestId

대회 ID

Table 25. HTTP Request Headers
Name Description

Authorization

Bearer {accessToken} (관리자)

HTTP Request
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 3,
  "itemOrder" : 2
} ]
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Table 26. Request Fields
Path Type Description

[]

Array

정렬 순서를 담은 팀 배열(모든 팀 다 보내주세요)

[].teamId

Number

정렬 순서를 변경할 팀 ID

[].itemOrder

Number

팀의 정렬 순서 (1부터 팀 개수까지)

5.3.1. ⚠️ 실패 케이스

❌ Case 1: CUSTOM 모드가 아님
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 3,
  "itemOrder" : 2
} ]
HTTP/1.1 403 Forbidden
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 80

{
  "message" : "CUSTOM 모드에서만 정렬을 수정할 수 있습니다."
}
❌ Case 2: request에 중복된 teamId 존재
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 1,
  "itemOrder" : 2
} ]
HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 52

{
  "message" : "중복된 팀ID가 있습니다."
}
Path Type Description

[]

Array

정렬 순서를 담은 팀 배열

[].teamId

Number

팀 ID(중복 존재)

[].itemOrder

Number

팀의 정렬 순서

❌ Case 3: request에 중복된 itemOrder 존재
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 3,
  "itemOrder" : 1
} ]
HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "중복된 itemOrder가 있습니다."
}
Path Type Description

[]

Array

정렬 순서를 담은 팀 배열

[].teamId

Number

팀 ID

[].itemOrder

Number

팀의 정렬 순서(중복 존재)

❌ Case 4: 요청 팀 개수와 저장된 팀 개수 다름
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 3,
  "itemOrder" : 2
} ]
HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 81

{
  "message" : "저장된 팀 개수와 request의 팀 개수가 다릅니다"
}
❌ Case 5: itemOrder가 팀 개수를 넘어감
PUT /contests/1/sort/custom HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 119
Host: localhost:8080

[ {
  "teamId" : 1,
  "itemOrder" : 1
}, {
  "teamId" : 2,
  "itemOrder" : 3
}, {
  "teamId" : 3,
  "itemOrder" : 2
} ]
HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 104

{
  "message" : "적절하지 않은 itemOrder입니다.(최대 팀 개수보다 초과된 itemOrder)"
}

6. 대회 관리

6.1. POST: 대회 생성

Table 27. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
POST /contests HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 61
Host: localhost:8080

{
  "contestName" : "제6회 해커톤",
  "categoryId" : 1
}
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 183

{
  "contestId" : 1,
  "contestName" : "제6회 해커톤",
  "categoryId" : 1,
  "categoryName" : "해커톤",
  "isCurrent" : true,
  "updatedAt" : "2026-03-28T15:18:11.720418165"
}
Table 28. Request Fields
Path Type Description

contestName

String

대회 이름

categoryId

Number

카테고리 ID

6.1.1. ⚠️ 실패 케이스

❌ Case 1: 동일한 대회명 존재
POST /contests HTTP/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 61
Host: localhost:8080

{
  "contestName" : "제6회 해커톤",
  "categoryId" : 1
}
HTTP/1.1 409 Conflict
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "동일한 대회명이 있습니다."
}
Path Type Description

contestName

String

이미 존재하는 대회 이름

categoryId

Number

카테고리 ID

6.2. PATCH: 대회 수정

대회 생성과 동일하게 이미 저장되어 있는 대회 이름은 저장 불가
Table 29. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 30. /contests/{contestId}
Parameter Description

contestId

대회 ID

HTTP Request
PATCH /contests/1 HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 61
Host: localhost:8080

{
  "contestName" : "제6회 해커톤",
  "categoryId" : 1
}
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Table 31. Request Fields
Path Type Description

contestName

String

대회 이름

categoryId

Number

카테고리 ID

6.3. DELETE: 대회 삭제

Table 32. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 33. /contests/{contestId}
Parameter Description

contestId

대회 ID

HTTP Request
DELETE /contests/1 HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

6.4. GET: 대회 목록 조회

HTTP Request
GET /contests HTTP/1.1
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 369

[ {
  "contestId" : 1,
  "contestName" : "제6회 해커톤",
  "categoryId" : 1,
  "categoryName" : "해커톤",
  "isCurrent" : true,
  "updatedAt" : "2026-03-28T15:18:11.419428501"
}, {
  "contestId" : 2,
  "contestName" : "CSE 캡스톤",
  "categoryId" : 2,
  "categoryName" : "캡스톤",
  "isCurrent" : false,
  "updatedAt" : "2026-03-28T15:18:11.419442155"
} ]
Table 34. Response Body’s Fields
Path Type Description

[]

Array

대회 목록

[].contestId

Number

대회 ID

[].contestName

String

대회 이름

[].categoryId

Number

카테고리 ID

[].categoryName

String

카테고리 이름

[].isCurrent

Boolean

현재 진행 대회 여부

[].updatedAt

String

수정 일시 (ISO-8601)

7. 투표 로그 관리

7.1. GET: 투표 로그 조회

Table 35. HTTP Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 36. /contests/{contestId}/vote-log
Parameter Description

contestId

대회 ID

page

페이지 번호 (0부터 시작)

size

페이지 크기

HTTP Request
GET /contests/1/vote-log?page=0&size=20 HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 775

{
  "content" : [ {
    "voterName" : "이옵스",
    "voterEmail" : "lee@pusan.ac.kr",
    "teamName" : "teamA",
    "votedAt" : "2026-03-28T15:18:11.388993425"
  }, {
    "voterName" : "김옵스",
    "voterEmail" : "kim@pusan.ac.kr",
    "teamName" : "teamB",
    "votedAt" : "2026-03-28T15:18:10.389001064"
  } ],
  "pageable" : {
    "pageNumber" : 0,
    "pageSize" : 20,
    "sort" : {
      "empty" : false,
      "sorted" : true,
      "unsorted" : false
    },
    "offset" : 0,
    "paged" : true,
    "unpaged" : false
  },
  "last" : true,
  "totalElements" : 2,
  "totalPages" : 1,
  "size" : 20,
  "number" : 0,
  "sort" : {
    "empty" : false,
    "sorted" : true,
    "unsorted" : false
  },
  "first" : true,
  "numberOfElements" : 2,
  "empty" : false
}
Table 37. Response Fields
Path Type Description

content[]

Array

투표 로그 목록 (최신순)

content[].voterName

String

투표자 이름

content[].voterEmail

String

투표자 이메일

content[].teamName

String

투표한 팀 이름

content[].votedAt

String

투표 시점 (ISO-8601)

pageable

Object

페이지 정보

last

Boolean

마지막 페이지 여부

totalPages

Number

전체 페이지 수

totalElements

Number

전체 요소 수

first

Boolean

첫 페이지 여부

size

Number

페이지 크기

number

Number

현재 페이지 번호

sort

Object

정렬 정보

numberOfElements

Number

현재 페이지 요소 수

empty

Boolean

비어있는 페이지 여부

8. 프로젝트 등록 현황 조회

8.1. GET: 대회 팀별 프로젝트 등록 현황 조회

Table 38. /contests/{contestId}/submissions
Parameter Description

contestId

대회의 고유 ID

Table 39. Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
GET /contests/1/submissions HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 521

[ {
  "teamId" : 1,
  "teamName" : "딥러닝 드리머즈",
  "projectName" : "AI 음성 번역기",
  "trackName" : "소프트웨어/인공지능",
  "isSubmitted" : true
}, {
  "teamId" : 2,
  "teamName" : "패킷 마스터즈",
  "projectName" : "실시간 트래픽 분석기",
  "trackName" : "네트워크/통신",
  "isSubmitted" : true
}, {
  "teamId" : 3,
  "teamName" : "시큐리티 가디언즈",
  "projectName" : "IoT 취약점 스캐너",
  "trackName" : "하드웨어/보안",
  "isSubmitted" : false
} ]
Table 40. Response Fields
Path Type Description

[]

Array

팀별 프로젝트 등록 현황 목록

[].teamId

Number

팀 ID

[].teamName

String

팀명

[].projectName

String

프로젝트명

[].trackName

String

트랙/분과명

[].isSubmitted

Boolean

프로젝트 제출 여부

8.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
Table 41. /contests/{contestId}/submissions
Parameter Description

contestId

존재하지 않는 대회 ID

GET /contests/999/submissions HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

9. 투표 랭킹 조회

9.1. GET: 대회 투표 랭킹 조회

Table 42. /contests/{contestId}/ranking
Parameter Description

contestId

대회의 고유 ID

Table 43. Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
GET /contests/1/ranking HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 595

[ {
  "rank" : 1,
  "teamId" : 10,
  "teamName" : "팀 A",
  "projectName" : "AI 번역기",
  "trackName" : "AI 트랙",
  "voteCount" : 150
}, {
  "rank" : 2,
  "teamId" : 11,
  "teamName" : "팀 B",
  "projectName" : "헬스 분석기",
  "trackName" : "헬스케어 트랙",
  "voteCount" : 120
}, {
  "rank" : 2,
  "teamId" : 12,
  "teamName" : "팀 C",
  "projectName" : "노인 케어봇",
  "trackName" : "AI 트랙",
  "voteCount" : 120
}, {
  "rank" : 4,
  "teamId" : 13,
  "teamName" : "팀 D",
  "projectName" : "감정 분석기",
  "trackName" : "AI 트랙",
  "voteCount" : 85
} ]
Table 44. Response Fields
Path Type Description

[]

Array

팀 랭킹 목록

[].rank

Number

투표 기준 순위 (Ranking) 예: 1-2-2-4

[].teamId

Number

팀 ID

[].teamName

String

팀명

[].projectName

String

프로젝트명

[].trackName

String

트랙/분과명

[].voteCount

Number

투표 수

9.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
Table 45. /contests/{contestId}/ranking
Parameter Description

contestId

존재하지 않는 대회 ID

GET /contests/999/ranking HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

10. 투표 집계 조회

10.1. GET: 대회 투표 집계 조회

Table 46. /contests/{contestId}/votes/statistics
Parameter Description

contestId

대회의 고유 ID

Table 47. Request Headers
Name Description

Authorization

Bearer admin.access.token

HTTP Request
GET /contests/1/votes/statistics HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 79

{
  "totalVotes" : 366,
  "totalVoters" : 249,
  "averageVotesPerVoter" : 1.5
}
Table 48. Response Fields
Path Type Description

totalVotes

Number

총 투표 수

totalVoters

Number

투표한 사람 수

averageVotesPerVoter

Number

1인당 평균 투표 수

10.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
Table 49. /contests/{contestId}/votes/statistics
Parameter Description

contestId

존재하지 않는 대회 ID

GET /contests/999/votes/statistics HTTP/1.1
Authorization: Bearer admin.access.token
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

11. 대회 팀 템플릿 설정 관리

11.1. GET: 대회의 템플릿 조회

Table 50. /contests/{contestId}/template
Parameter Description

contestId

대회 ID

HTTP Request
GET /contests/1/template HTTP/1.1
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 359

{
  "trackRequired" : true,
  "projectNameRequired" : true,
  "teamNameRequired" : true,
  "leaderRequired" : true,
  "teamMembersRequired" : true,
  "professorRequired" : true,
  "githubPathRequired" : true,
  "youTubePathRequired" : true,
  "productionPathRequired" : true,
  "overviewRequired" : true,
  "posterRequired" : true,
  "imagesRequired" : true
}
Table 51. Response Fields
Path Type Description

trackRequired

Boolean

트랙/분과 필수 여부

projectNameRequired

Boolean

프로젝트명 필수 여부

teamNameRequired

Boolean

팀명 필수 여부

leaderRequired

Boolean

팀장 필수 여부

teamMembersRequired

Boolean

팀원 필수 여부

professorRequired

Boolean

지도교수 필수 여부

githubPathRequired

Boolean

GitHub 링크 필수 여부

youTubePathRequired

Boolean

YouTube 링크 필수 여부

productionPathRequired

Boolean

배포 링크 필수 여부

overviewRequired

Boolean

프로젝트 개요 필수 여부

posterRequired

Boolean

포스터 필수 여부

imagesRequired

Boolean

이미지 필수 여부

11.1.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
Table 52. /contests/{contestId}/template
Parameter Description

contestId

존재하지 않는 대회 ID

GET /contests/999/template HTTP/1.1
Host: localhost:8080
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

11.2. PUT: 대회의 템플릿 수정

Table 53. /contests/{contestId}/template
Parameter Description

contestId

대회 ID

Table 54. Request Headers
Name Description

Authorization

Bearer admin.access.token

Table 55. Request Fields
Path Type Description

trackRequired

Boolean

트랙/분과 필수 여부

projectNameRequired

Boolean

프로젝트명 필수 여부

teamNameRequired

Boolean

팀명 필수 여부

leaderRequired

Boolean

팀장 필수 여부

teamMembersRequired

Boolean

팀원 필수 여부

professorRequired

Boolean

지도교수 필수 여부

githubPathRequired

Boolean

GitHub 링크 필수 여부

youTubePathRequired

Boolean

YouTube 링크 필수 여부

productionPathRequired

Boolean

배포 링크 필수 여부

overviewRequired

Boolean

프로젝트 개요 필수 여부

posterRequired

Boolean

포스터 필수 여부

imagesRequired

Boolean

이미지 필수 여부

HTTP Request
PUT /contests/1/template HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 371
Host: localhost:8080

{
  "trackRequired" : false,
  "projectNameRequired" : false,
  "teamNameRequired" : false,
  "leaderRequired" : false,
  "teamMembersRequired" : false,
  "professorRequired" : false,
  "githubPathRequired" : false,
  "youTubePathRequired" : false,
  "productionPathRequired" : false,
  "overviewRequired" : false,
  "posterRequired" : false,
  "imagesRequired" : false
}
HTTP Response
HTTP/1.1 204 No Content
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

11.2.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회
Table 56. /contests/{contestId}/template
Parameter Description

contestId

존재하지 않는 대회 ID

PUT /contests/999/template HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer admin.access.token
Content-Length: 371
Host: localhost:8080

{
  "trackRequired" : false,
  "projectNameRequired" : false,
  "teamNameRequired" : false,
  "leaderRequired" : false,
  "teamMembersRequired" : false,
  "professorRequired" : false,
  "githubPathRequired" : false,
  "youTubePathRequired" : false,
  "productionPathRequired" : false,
  "overviewRequired" : false,
  "posterRequired" : false,
  "imagesRequired" : false
}
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}

12. 대회 전체 팀 조회

12.1. GET: 대회의 팀 목록 조회 (비회원용)

비회원용 메인 페이지 API입니다. isLiked`와 `isVoted 값이 항상 false 입니다.
Table 57. /contests/{contestId}/teams/public
Parameter Description

contestId

대회의 고유 ID

HTTP Request
GET /contests/1/teams/public HTTP/1.1
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 410

[ {
  "teamId" : 1,
  "teamName" : "team1",
  "projectName" : "team1 Project",
  "isLiked" : false,
  "isVoted" : false,
  "awards" : [ {
    "awardName" : "대상",
    "awardColor" : "#FF0000"
  }, {
    "awardName" : "우수상",
    "awardColor" : "#00A3FF"
  } ]
}, {
  "teamId" : 2,
  "teamName" : "team2",
  "projectName" : "team2 Project",
  "isLiked" : false,
  "isVoted" : false,
  "awards" : [ ]
} ]
Table 58. Response Body’s Fields
Path Type Description

[]

Array

팀 목록

[].teamId

Number

팀 ID

[].teamName

String

팀명

[].projectName

String

프로젝트명

[].isLiked

Boolean

좋아요 여부 (항상 false)

[].isVoted

Boolean

투표 여부 (항상 false)

[].awards

Array

수상 목록

[].awards[].awardName

String

수상명

[].awards[].awardColor

String

수상 색상

12.2. GET: 대회의 팀 목록 조회 (회원용 - 미투표 기간)

회원만 접근 가능한 메인 페이지용 API입니다. 미투표 기간에는 로그인한 사용자의 isLiked 여부가 포함됩니다.
Table 59. /contests/{contestId}/teams
Parameter Description

contestId

대회의 고유 ID

Table 60. Request Headers
Name Description

Authorization

Bearer member.access.token

HTTP Request
GET /contests/1/teams HTTP/1.1
Authorization: Bearer member.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 342

[ {
  "teamId" : 1,
  "teamName" : "team1",
  "projectName" : "team1 Project",
  "isLiked" : true,
  "isVoted" : false,
  "awards" : [ {
    "awardName" : "대상",
    "awardColor" : "#FF0000"
  } ]
}, {
  "teamId" : 2,
  "teamName" : "team2",
  "projectName" : "team2 Project",
  "isLiked" : false,
  "isVoted" : false,
  "awards" : [ ]
} ]
Table 61. Response Body’s Fields
Path Type Description

[]

Array

팀 목록

[].teamId

Number

팀 ID

[].teamName

String

팀명

[].projectName

String

프로젝트명

[].isLiked

Boolean

좋아요 여부 (투표 기간인 경우 false, 회원은 로그인한 사용자의 좋아요 여부에 따라)

[].isVoted

Boolean

투표 여부 (투표 기간이 아닌 경우 false, 회원은 로그인한 사용자의 투표 여부에 따라)

[].awards

Array

수상 목록

[].awards[].awardName

String

수상명

[].awards[].awardColor

String

수상 색상

12.3. GET: 대회의 팀 목록 조회 (회원용 - 투표 기간)

회원만 접근 가능한 메인 페이지용 API입니다. 투표 기간에는 로그인한 사용자의 isVoted 여부가 포함됩니다.
Table 62. /contests/{contestId}/teams
Parameter Description

contestId

대회의 고유 ID

Table 63. Request Headers
Name Description

Authorization

Bearer member.access.token

HTTP Request
GET /contests/1/teams HTTP/1.1
Authorization: Bearer member.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 342

[ {
  "teamId" : 1,
  "teamName" : "team1",
  "projectName" : "team1 Project",
  "isLiked" : false,
  "isVoted" : true,
  "awards" : [ {
    "awardName" : "대상",
    "awardColor" : "#FF0000"
  } ]
}, {
  "teamId" : 2,
  "teamName" : "team2",
  "projectName" : "team2 Project",
  "isLiked" : false,
  "isVoted" : false,
  "awards" : [ ]
} ]
Table 64. Response Body’s Fields
Path Type Description

[]

Array

팀 목록

[].teamId

Number

팀 ID

[].teamName

String

팀명

[].projectName

String

프로젝트명

[].isLiked

Boolean

좋아요 여부 (투표 기간인 경우 false, 회원은 로그인한 사용자의 좋아요 여부에 따라)

[].isVoted

Boolean

투표 여부 (투표 기간이 아닌 경우 false, 회원은 로그인한 사용자의 투표 여부에 따라)

[].awards

Array

수상 목록

[].awards[].awardName

String

수상명

[].awards[].awardColor

String

수상 색상

12.3.1. ⚠️ 실패 케이스

❌ Case 1: 존재하지 않는 대회 ID
HTTP Request
GET /contests/999/teams HTTP/1.1
Authorization: Bearer member.access.token
Host: localhost:8080
HTTP Response
HTTP/1.1 404 Not Found
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 56

{
  "message" : "존재하지 않는 대회입니다."
}
Table 65. /contests/{contestId}/teams
Parameter Description

contestId

존재하지 않는 대회 ID