Shared Authentication

Toss anonymous login

POST /api/v1/auth/toss/anonymous HTTP/1.1
Content-Type: application/json
Content-Length: 40
Host: localhost:8080

{"club":"wakeup","code":"one-time-code"}
Path Type Description

club

String

workout, wakeup, diet, attendance

code

String

User.createAnonymousKeyAuthCode()의 일회용 인증 코드

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 119

{"user":{"id":"dbcec423-e8aa-4195-a82e-9956bf0994df"},"accessToken":"signed-jwt","tokenType":"Bearer","expiresIn":3600}
Path Type Description

user.id

String

클럽 범위의 공통 인증 사용자 UUID

accessToken

String

해당 클럽 JWT

tokenType

String

Bearer

expiresIn

Number

JWT 유효기간 (초)

Wakeup

JWT가 필요한 API는 Authorization: Bearer 헤더와 club=wakeup claim을 사용합니다. 출석 날짜는 한국 시간 기준이며, 중복 출석은 기존 출석을 반환합니다.

me/get

GET /api/v1/wakeup/me HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 118

{"id":"10000000-0000-0000-0000-000000000001","name":"아침형","tossUserKey":null,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

공통 인증 사용자 UUID

name

String

이름

tossUserKey

Null

기존 토스 사용자 키 (nullable)

createdAt

String

가입 시각 (UTC)

me/create

POST /api/v1/wakeup/me HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 20
Host: localhost:8080

{"name":"아침형"}
Name Description

Authorization

Wakeup JWT (Bearer)

Path Type Description

name

String

1~16자 이름

HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 118

{"id":"10000000-0000-0000-0000-000000000001","name":"아침형","tossUserKey":null,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

공통 인증 사용자 UUID

name

String

이름

tossUserKey

Null

기존 토스 사용자 키 (nullable)

createdAt

String

가입 시각 (UTC)

me/update

PATCH /api/v1/wakeup/me HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 20
Host: localhost:8080

{"name":"새이름"}
Name Description

Authorization

Wakeup JWT (Bearer)

Path Type Description

name

String

1~16자 이름

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 118

{"id":"10000000-0000-0000-0000-000000000001","name":"새이름","tossUserKey":null,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

공통 인증 사용자 UUID

name

String

이름

tossUserKey

Null

기존 토스 사용자 키 (nullable)

createdAt

String

가입 시각 (UTC)

rooms/list

GET /api/v1/wakeup/rooms HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 276

[{"id":"20000000-0000-0000-0000-000000000001","code":"ABCDEF","name":"아침방","activationTime":"06:30","activationDurationMin":10,"capacity":8,"activeWeekdays":[1,2,3,4,5],"ownerId":"10000000-0000-0000-0000-000000000001","memberCount":1,"createdAt":"2026-09-29T00:00:00Z"}]
Path Type Description

[].id

String

방 UUID

[].code

String

참여 코드

[].name

String

방 이름

[].activationTime

String

기상 시각 (HH:mm, 한국 시간)

[].activationDurationMin

Number

기상 버튼 활성 시간 (분)

[].capacity

Number

정원

[].activeWeekdays

Array

활성 요일 (일=0 ~ 토=6)

[].ownerId

String

방장 UUID

[].memberCount

Number

현재 멤버 수

[].createdAt

String

생성 시각 (UTC)

rooms/create

POST /api/v1/wakeup/rooms HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 74
Host: localhost:8080

{"activeWeekdays":[1,2,3,4,5],"activationTime":"06:30","name":"아침방"}
Name Description

Authorization

Wakeup JWT (Bearer)

Path Type Description

name

String

1~16자 방 이름

activationTime

String

04:00~11:55 기상 시각

activeWeekdays

Array

활성 요일

HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 274

{"id":"20000000-0000-0000-0000-000000000001","code":"ABCDEF","name":"아침방","activationTime":"06:30","activationDurationMin":10,"capacity":8,"activeWeekdays":[1,2,3,4,5],"ownerId":"10000000-0000-0000-0000-000000000001","memberCount":1,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

방 UUID

code

String

참여 코드

name

String

방 이름

activationTime

String

기상 시각 (HH:mm, 한국 시간)

activationDurationMin

Number

기상 버튼 활성 시간 (분)

capacity

Number

정원

activeWeekdays

Array

활성 요일 (일=0 ~ 토=6)

ownerId

String

방장 UUID

memberCount

Number

현재 멤버 수

createdAt

String

생성 시각 (UTC)

rooms/update

PATCH /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001 HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 74
Host: localhost:8080

{"activeWeekdays":[1,2,3,4,5],"activationTime":"06:30","name":"아침방"}
Name Description

Authorization

Wakeup JWT (Bearer)

Table 1. /api/v1/wakeup/rooms/{roomId}
Parameter Description

roomId

방 UUID

Path Type Description

name

String

1~16자 방 이름

activationTime

String

04:00~11:55 기상 시각

activeWeekdays

Array

활성 요일

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 274

{"id":"20000000-0000-0000-0000-000000000001","code":"ABCDEF","name":"아침방","activationTime":"06:30","activationDurationMin":10,"capacity":8,"activeWeekdays":[1,2,3,4,5],"ownerId":"10000000-0000-0000-0000-000000000001","memberCount":1,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

방 UUID

code

String

참여 코드

name

String

방 이름

activationTime

String

기상 시각 (HH:mm, 한국 시간)

activationDurationMin

Number

기상 버튼 활성 시간 (분)

capacity

Number

정원

activeWeekdays

Array

활성 요일 (일=0 ~ 토=6)

ownerId

String

방장 UUID

memberCount

Number

현재 멤버 수

createdAt

String

생성 시각 (UTC)

rooms/delete

DELETE /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001 HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup 클럽 JWT (Bearer)

Table 2. /api/v1/wakeup/rooms/{roomId}
Parameter Description

roomId

방 UUID

HTTP/1.1 204 No Content

rooms/join

POST /api/v1/wakeup/rooms/join HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 17
Host: localhost:8080

{"code":"ABCDEF"}
Name Description

Authorization

Wakeup JWT (Bearer)

Path Type Description

code

String

방 참여 코드

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 274

{"id":"20000000-0000-0000-0000-000000000001","code":"ABCDEF","name":"아침방","activationTime":"06:30","activationDurationMin":10,"capacity":8,"activeWeekdays":[1,2,3,4,5],"ownerId":"10000000-0000-0000-0000-000000000001","memberCount":1,"createdAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

방 UUID

code

String

참여 코드

name

String

방 이름

activationTime

String

기상 시각 (HH:mm, 한국 시간)

activationDurationMin

Number

기상 버튼 활성 시간 (분)

capacity

Number

정원

activeWeekdays

Array

활성 요일 (일=0 ~ 토=6)

ownerId

String

방장 UUID

memberCount

Number

현재 멤버 수

createdAt

String

생성 시각 (UTC)

rooms/leave

DELETE /api/v1/wakeup/rooms/membership HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup 클럽 JWT (Bearer)

HTTP/1.1 204 No Content

membership/get

GET /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001/membership HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

Table 3. /api/v1/wakeup/rooms/{roomId}/membership
Parameter Description

roomId

방 UUID

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 92

{"notifyEnabled":false,"notificationAgreementAt":null,"reminderOffsetMin":0,"nickname":null}
Path Type Description

notifyEnabled

Boolean

알림 수신 여부

notificationAgreementAt

Null

알림 동의 시각 (nullable)

reminderOffsetMin

Number

기상 시각 이전 알림 분 (0~60)

nickname

Null

방 닉네임 (nullable)

membership/update

PATCH /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001/membership HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Content-Length: 87
Host: localhost:8080

{"notifyEnabled":true,"nickname":"방장","reminderOffsetMin":10,"clearNickname":false}
Name Description

Authorization

Wakeup JWT (Bearer)

Table 4. /api/v1/wakeup/rooms/{roomId}/membership
Parameter Description

roomId

방 UUID

Path Type Description

notifyEnabled

Boolean

알림 수신 여부

reminderOffsetMin

Number

기상 시각 이전 알림 분 (0~60)

nickname

String

1~16자 방 닉네임

clearNickname

Boolean

닉네임 삭제 여부

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 114

{"notifyEnabled":true,"notificationAgreementAt":"2026-09-29T00:00:00Z","reminderOffsetMin":10,"nickname":"방장"}
Path Type Description

notifyEnabled

Boolean

알림 수신 여부

notificationAgreementAt

String

알림 동의 시각 (nullable)

reminderOffsetMin

Number

기상 시각 이전 알림 분 (0~60)

nickname

String

방 닉네임 (nullable)

members/list

GET /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001/members HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

Table 5. /api/v1/wakeup/rooms/{roomId}/members
Parameter Description

roomId

방 UUID

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 67

[{"userId":"10000000-0000-0000-0000-000000000001","name":"방장"}]
Path Type Description

[].userId

String

멤버 UUID

[].name

String

방 닉네임 또는 사용자 이름

check-ins/create

POST /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001/check-ins HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

Table 6. /api/v1/wakeup/rooms/{roomId}/check-ins
Parameter Description

roomId

방 UUID

HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 168

{"id":"aa48bbe2-2d67-4dbb-bf33-cd0b8ec22477","userId":"10000000-0000-0000-0000-000000000001","userName":"방장","date":"2026-09-29","pressedAt":"2026-09-29T00:00:00Z"}
Path Type Description

id

String

출석 UUID

userId

String

출석 사용자 UUID

userName

String

출석 당시 이름

date

String

출석 날짜 (한국 시간)

pressedAt

String

서버에서 기록한 버튼 입력 시각 (UTC)

check-ins/list

GET /api/v1/wakeup/rooms/20000000-0000-0000-0000-000000000001/check-ins HTTP/1.1
Content-Type: application/json
Authorization: Bearer documented-token
Host: localhost:8080
Name Description

Authorization

Wakeup JWT (Bearer)

Table 7. /api/v1/wakeup/rooms/{roomId}/check-ins
Parameter Description

roomId

방 UUID

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 170

[{"id":"027a9cca-9464-4223-a3d8-a458f4c1e551","userId":"10000000-0000-0000-0000-000000000001","userName":"방장","date":"2026-09-29","pressedAt":"2026-09-29T00:00:00Z"}]
Path Type Description

[].id

String

출석 UUID

[].userId

String

출석 사용자 UUID

[].userName

String

출석 당시 이름

[].date

String

출석 날짜 (한국 시간)

[].pressedAt

String

서버에서 기록한 버튼 입력 시각 (UTC)

Attendance

Attendance Image Comparison

입실 사진과 퇴실 사진의 전체 색 분포를 비교합니다. 객체가 동일하다는 증명이나 출석 확정 결과가 아니며, 사진과 출석 기록을 저장하지 않습니다. 방·입퇴실 기록은 현재 클라이언트의 Supabase 연동에서 처리합니다.

  • 메서드/경로: POST /api/v1/attendance/images/compare

  • 인증: 공개 API이며 Authorization 헤더 없이 호출할 수 있습니다.

  • 요청: multipart/form-data

  • 성공: 200 OK, JSON 객체를 직접 반환합니다.

요청

`reference`는 입실 사진, `candidate`는 퇴실 사진입니다. 파일 파트는 이 두 이름으로 각각 정확히 하나씩 보내며, 다른 파일 파트나 중복 파일은 허용하지 않습니다. 파일명·Content-Type만으로 형식을 판단하지 않고 실제 JPEG 바이트와 디코딩 가능 여부를 검증합니다.

제약 기준

파일 크기

파일당 최대 8 MiB (8 × 1024 × 1024 bytes)

전체 multipart 요청

최대 17 MiB (multipart 부가 데이터 포함, 기본 설정)

픽셀 수

이미지당 최대 4,000,000 pixels, 디코딩 전에 검사

요청 빈도

서버의 ImageService 인스턴스당 1분 고정 구간 최대 120회

동시 비교

ImageService 인스턴스당 최대 4개, 대기 없이 초과 요청 거절

요청 제한은 사용자별 한도가 아닙니다. 여러 서버 인스턴스가 공유하는 전역 한도도 아닙니다. 빈도 검사 후 동시 실행 한도를 검사하므로 동시 실행 초과 요청도 빈도에 포함됩니다.

$ curl 'http://localhost:8080/api/v1/attendance/images/compare' -i -X POST \
    -H 'Content-Type: multipart/form-data;charset=ISO-8859-1' \
    -F 'reference=@check-in.jpg;type=image/jpeg' \
    -F 'candidate=@check-out.jpg;type=image/jpeg'
Part Description

reference

입실 JPEG 사진, 최대 8 MiB·4,000,000 pixels, 정확히 하나

candidate

퇴실 JPEG 사진, 최대 8 MiB·4,000,000 pixels, 정확히 하나

성공 응답

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 38

{"verdict":"MATCH","reason":"similar"}
Path Type Description

verdict

String

색 분포 판정: MATCH, NON_MATCH, UNDECIDABLE

reason

String

판정 사유: similar, different, uncertain

verdict reason 클라이언트 처리

MATCH

similar

색 분포가 유사합니다. 출석 처리에는 별도 업무 규칙을 적용합니다.

NON_MATCH

different

색 분포가 다릅니다. 사진과 촬영 환경을 확인하도록 안내합니다.

UNDECIDABLE

uncertain

판정이 애매합니다. 확정 성공으로 처리하지 않고 확인을 안내합니다.

세 판정 모두 비교가 완료된 정상 200 응답입니다. HSV 유사도 점수는 공개 응답에 포함하지 않으며 객체 동일성·확률로 해석하지 않습니다. 배경과 조명에 영향을 받고 서로 다른 객체도 비슷한 색 분포를 가지면 MATCH가 될 수 있습니다.

오류와 재시도

업무 오류는 application/problem+json`의 ProblemDetail로 반환합니다. 클라이언트는 `code`로 분기하고 `detail 문구를 비교하지 않습니다.

HTTP code 원인과 처리

400

missing_image

파일 파트 누락·중복·추가. 두 파일 파트를 정확히 구성합니다.

413

image_too_large

파일·요청 크기 또는 픽셀 수 초과. 사진을 축소합니다.

415

unsupported_image_type

JPEG 형식 미지원. JPEG로 변환합니다.

422

invalid_image

빈 파일 또는 디코딩 불가. 정상 사진을 다시 선택합니다.

429

rate_limited

요청 빈도 또는 동시 비교 한도 초과. 지연 후 제한된 횟수로 재시도합니다.

503

comparison_unavailable

비교 계산 중 장애. 잠시 후 제한된 횟수로 재시도합니다.

`Retry-After`는 현재 제공하지 않습니다. 아래 예제는 필수 파일 누락에 대한 실제 테스트 응답입니다.

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Length: 163

{"detail":"Both image parts are required exactly once.","instance":"/api/v1/attendance/images/compare","status":400,"title":"Missing image","code":"missing_image"}
Path Type Description

type

String

문제 유형 URI. 기본 유형일 때 생략될 수 있음

title

String

오류 제목

status

Number

HTTP 상태 코드

detail

String

오류 설명. 분기 조건으로 사용하지 않음

instance

String

오류가 발생한 요청 경로

code

String

클라이언트 분기용 오류 코드: missing_image

처리 흐름

클라이언트 → 공개 API (JWT 인증 불필요) → ImageController의 파일 파트 검증 → ImageService의 요청·동시 실행 제한 → JPEG·크기·픽셀 검증 → HSV 비교 → verdict/reason 응답. 이 흐름은 DB나 Toss를 호출하지 않습니다.