API 명세서 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

주요 변경사항

25.04.17. 피드백 반영 25.04.19. API 명세서문서화 25.05.28. API 수정(GET /api/album/{albumId}, PATCH /api/album/{albumId}/cluster/{clusterId}, POST /api/album)


📦 공통 Error Response

❗️401 Unauthorized – Access Token 만료

{
  "code": "ACCESS_TOKEN_EXPIRED",
  "message": "access token이 만료되었습니다.",
  "data": null
}

❗️401 Unauthorized – Refresh Token 만료

{
  "code": "REFRESH_TOKEN_EXPIRED",
  "message": "refresh token이 만료되었습니다.",
  "data": null
}

❗️500 Internal Server Error – 서버 오류

{
  "code": "INTERNAL_SERVER_ERROR",
  "message": "서버 오류가 발생했습니다.",
  "data": null
}

공용 API

✅ Presigned URL 발급

  • Endpoint: /api/presigned-url
  • HTTP Method: POST

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Request Body

    {
      "pictures": [
        { "pictureName": "photo1.png", "pictureType": "image/png" },
        { "pictureName": "photo2.jpeg", "pictureType": "image/jpeg" },
        { "pictureName": "photo3.webp", "pictureType": "image/webp" }
      ]
    }
    

✅ Success Response

  • 200 OK – Presigned URL 발급 성공 (PRESIGNED_URL_ISSUED)

    {
      "presignedFiles": [
        {
          "pictureName": "photo1.png",
          "presignedUrl": "https://bucket.s3.amazonaws.com/photo1.png?...",
          "pictureURL": "https://bucket.s3.amazonaws.com/photo1.png"
        },
        {
          "pictureName": "photo2.jpeg",
          "presignedUrl": "https://bucket.s3.amazonaws.com/photo2.jpeg?...",
          "pictureURL": "https://bucket.s3.amazonaws.com/photo2.jpeg"
        },
        {
          "pictureName": "photo3.webp",
          "presignedUrl": "https://bucket.s3.amazonaws.com/photo3.webp?...",
          "pictureURL": "https://bucket.s3.amazonaws.com/photo3.webp"
        }
      ]
    }
    

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 프론트엔드에서 S3에 직접 이미지를 업로드할 수 있도록 Presigned URL을 발급합니다.
    • 클라이언트는 해당 URL로 이미지를 업로드하고, 응답으로 받은 pictureURL을 앨범 생성, 앨범에 사진 추가, 프로필 이미지 업로드 등의 API에 활용합니다.
    • 이 API는 앨범 생성 전, 또는 앨범에 사진을 추가하기 전에 실행되는 API입니다.
  • 요청자는 해당 앨범의 멤버여야 하며, 그렇지 않으면 403 응답이 반환됩니다.
  • 이 구조는 대용량 이미지 처리 시 백엔드 서버의 부담을 줄이고, 업로드 속도를 최적화하는 데 유리합니다.
  • Presigned URL은 이미지 업로드만을 위해 사용되어야 하므로 짧은 수명을 가집니다.(5분 / 개발 중 실험을 통해 수명 확정 예정)

유저 관련

✅ 로그인 요청

  • Endpoint: /api/auth
  • HTTP Method: GET

📥 Request

  • Request Params: 없음
  • Request Body: 없음

📤 Response

  • 302 Found

    사용자를 카카오 로그인 페이지로 리디렉션

    Location: https://kauth.kakao.com/oauth/authorize?response_type=code&client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}
    

⚠️ Error Response

  • 에러 발생 없음 (리디렉션 전용 API)

🧩 설계 근거 및 시나리오

  • 이 API는 온기 서비스에서 카카오 로그인 페이지로 이동시키기 위한 리디렉션용 API입니다.
  • 클라이언트는 이 URL에 접근하면 카카오의 인증 페이지로 이동하고, 사용자는 카카오 로그인을 수행한 후 authorization code를 포함한 응답을 받게 됩니다.
  • 그 후 클라이언트는 /api/auth/callback으로 백엔드 서버에 해당 코드를 넘겨 토큰 발급 절차를 진행합니다.

✅ 로그인 (토큰 발급)

  • Endpoint: /api/auth/callback?code={authorization_code}
  • HTTP Method: POST

📥 Request

  • Request Params

    • authorization_code (String): 카카오에서 발급한 authorization code
  • Request Body

    • 없음

📤 Response

✅ Success Response

  • 200 OK – 이미 등록된 사용자 (USER_ALREADY_REGISTERED)

    {
      "code": "USER_ALREADY_REGISTERED",
      "accessToken": "access_token_value",
      "refreshTokenExpiresIn": 1209600,
      "refreshToken": "refresh_token_value",
      "user": {
        "userId": 1,
        "nickname": "gray_123!",
        "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
        "cacheTtl": 300
      }
    }
    
  • 200 OK – 신규 사용자 (USER_NOT_REGISTERED)

    {
      "code": "USER_NOT_REGISTERED",
      "accessToken": "access_token_value",
      "refreshTokenExpiresIn": 1209600,
      "refreshToken": "refresh_token_value",
      "user": {
        "userId": 1,
        "nickname": "gray_123!",
        "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
        "cacheTtl": 300
      }
    }
    

⚠️ Error Response

  • 400 Bad Request

    {
      "code": "INVALID_REQUEST",
      "message": "인가 코드가 유효하지 않습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 카카오 로그인 후 프론트로 전달한 authorization code를 바탕으로 온기 서비스 전용 access token과 refresh token을 발급합니다.
  • 전달된 인가 코드를 기반으로 POST https://kauth.kakao.com/oauth/token 로 kakao api 사용 목적의 access token과 refresh token을 발급받습니다.
    • 전달받은 access token을 사용하여 GET https://kapi.kakao.com/v2/user/me 로 유저 정보를 요청합니다.
    • 제공받은 id를 user 테이블의 provider_id와 비교하여 가입 여부를 확인하여 로그인 처리하고, 미가입 유저 시 회원가입 처리시킵니다.
    • 온기 서비스를 위한 별도의 access_token과 refresh_token을 생성하여 응답 body에 포함합니다.
  • 사용자가 이미 가입된 경우와 처음 로그인하는 경우를 구분해 응답의 code 필드에 상태를 명시합니다.
  • 응답에는 인증 토큰과 함께 유저 정보가 포함되며, 이후 서비스 이용 시 이 토큰이 인증 수단으로 사용됩니다.

✅ 토큰 재발급

  • Endpoint: /api/auth/refresh
  • HTTP Method: POST

📥 Request

  • Request Params: 없음

  • Request Body

    {
      "refreshToken": "refresh_token_value"
    }
    

📤 Response

✅ Success Response

  • 200 OK – 토큰 재발급 성공 (TOKEN_REFRESH_SUCCESS)

    {
      "code": "TOKEN_REFRESH_SUCCESS",
      "message": "토큰이 재발급되었습니다.",
      "accessToken": "access_token_value"
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 클라이언트가 보유하고 있는 Refresh Token을 이용해 Access Token을 재발급받기 위해 사용됩니다.
  • 사용자는 로그인 후 일정 시간이 지나면 Access Token이 만료되기 때문에, 별도로 저장해둔 Refresh Token으로 /api/auth/reissue API를 호출하여 새로운 Access Token을 받게 됩니다.
  • Refresh Token 자체가 만료되었거나 잘못된 경우에는 401 또는 400 오류가 발생합니다.

✅ 로그아웃

  • Endpoint: /api/auth
  • HTTP Method: POST

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Request Params: 없음

  • Request Body

    {
      "refreshToken": "refresh_token_value"
    }
    

✅ Success Response

  • 200 OK – 로그아웃 성공 (LOGOUT_SUCCESS)

    {
      "code": "LOGOUT_SUCCESS",
      "message": "로그아웃이 완료되었습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 서비스에서 로그아웃할 때 호출됩니다.
  • Access Token은 헤더로 전달되며, Refresh Token은 본문에 포함되어야 합니다.
  • 로그아웃 시 서버는 해당 Refresh Token을 무효화하고, 클라이언트는 보유 중인 인증 정보를 삭제하게 됩니다.
  • 토큰이 누락되었거나 유효하지 않은 경우 해당 상황에 따른 공통 에러 응답이 반환됩니다.

✅ 유저 정보 확인

  • Endpoint: /api/user/{userId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params: 없음
  • Request Body: 없음

✅ Success Response

  • 200 OK – 유저 정보 조회 성공 (USER_INFO_SUCCESS)

    {
      "code": "USER_INFO_SUCCESS",
      "message": "유저 조회 완료했습니다.",
      "user": {
        "userId": 1,
        "nickname": "gray_123!",
        "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
        "cacheTtl": 300
      }
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 클라이언트가 보유한 Access Token을 기반으로 현재 로그인된 유저의 정보를 조회합니다.
  • 프로필, 닉네임 등 기본 정보와 함께 cacheTtl 등의 캐시 유효 시간도 포함되어 있으며, 인증된 사용자만 호출 가능하고 Authorization 헤더가 반드시 포함되어야 합니다.

✅ 유저정보 수정

  • Endpoint: /api/user/{userId}
  • HTTP Method: PUT

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Request Params

    • userId (Long, 필수): 수정할 유저의 ID
  • Request Body

    {
      "nickname": "gray_321!",
      "profileImageURL" : "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg"
    }
    

✅ Success Response

  • 200 OK – 유저 닉네임 변경 성공 (USER_NICKNAME_UPDATE_SUCCESS)

    {
      "code": "USER_NICKNAME_UPDATE_SUCCESS",
      "message": "유저 닉네임 변경 완료했습니다.",
      "user": {
        "userId": 1,
        "nickname": "gray_321!",
        "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
        "cacheTtl": 300
      }
    }
    

⚠️ Error Response

  • 400 Bad Request – 유효하지 않은 닉네임

    {
      "code": "INVALID_VALUE",
      "message": "유효한 닉네임이 아닙니다.",
      "data": null
    }
    
  • 403 Frobidden – 타 유저정보 수정 시도

    {
      "code": "USER_UPDATE_DENIED",
      "message": "타인의 유저정보는 수정할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 인증된 사용자가 닉네임과 프로필 이미지를 수정하는 기능을 제공합니다.
  • 닉네임은 유효성 검사를 거쳐야 하며, 기존 닉네임과 중복되거나 규칙에 어긋날 경우 400 오류가 반환됩니다.
  • 요청이 성공하면 변경된 닉네임과 프로필 사진의 URL을 포함한 유저 정보를 반환합니다.
    • 프론트는 기존 캐싱하고 있던 유저정보를 새 정보로 교체합니다.

✅ 유저 사진 일간 개수 월별 조회

  • Endpoint: /api/user/statistics/picture/?yearmonth={yearMonth}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • yearMonth (optional, yyyy-MM 형식): 조회할 연월
      • 미전달 시 전체 등록 사진 수만 반환
      • 전달 시 해당 월의 사진 통계 기록 반환
  • Request Body: 없음

✅ Success Response

  • 200 OK – 유저 사진 총 개수 조회 성공 (USER_PICTURE_TOTAL_STATISTICS_SUCCESS)

    {
      "code": "USER_PICTURE_TOTAL_STATISTICS_SUCCESS",
      "message": "유저 등록 사진 수 조회 성공",
      "data": {
        "count": 10
      }
    }
    
  • 200 OK – 유저 사진 일간 통계 조회 성공 (USER_PICTURE_MONTHLY_STATISTICS_SUCCESS)

    {
      "code": "USER_PICTURE_MONTHLY_STATISTICS_SUCCESS",
      "message": "월단위 일간 사진 등록 수 조회 성공",
      "data": {
        "yearMonth": "2025-04",
        "dailyImageCount": {
          "2025-04-01": 3,
          "2025-04-02": 0,
          "2025-04-03": 7,
          ...
          "2025-04-30": 2
        }
      }
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 해당 월(yearMonth)에 각 날짜별로 업로드한 사진 수를 조회할 수 있도록 합니다.
  • 이를 통해 클라이언트는 월별 업로드 추이를 시각화하거나 캘린더 형태의 통계 UI를 제공할 수 있습니다.
  • yearMonth를 Query Parameter로 입력하며, 양식은 yyyy-mm입니다. 전체 등록 사진 개수를 조회하고 싶으면 입력하지 않을 수 있습니다.
    • yyyy-mm의 경우
      • yyyy-MM-dd와 일별 사진 수가 key-value 형식으로 구성됩니다.
    • 입력하지 않을 경우
      • 유저가 등록한 사진의 총 개수를 count를 통해 나타냅니다.

✅ 유저가 방문한 장소 조회

  • Endpoint: /api/user/statistics/place?yearMonth={yearMonth}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • yearMonth (optional, yyyy-MM 형식): 조회할 연월
      • 미전달 시 전체 방문 장소 수만 반환
      • 전달 시 해당 월의 상세 방문 기록 반환
  • Request Body: 없음

✅ Success Response

  • 200 OK – 유저 방문 모든 장소 숫자 성공 (USER_ALL_PLACE_SUCCESS)

    {
      "code": "USER_ALL_PLACE_SUCCESS",
      "message": "유저 방문 장소 조회 성공",
      "data": {
    	  "count": 23
      }
    }
    
  • 200 OK – 유저 방문 장소 조회 성공 (USER_PLACE_SUCCESS)

    {
      "code": "USER_PLACE_SUCCESS",
      "message": "유저 방문 장소 조회 성공",
      "data": [
        {
          "city": "강원도",
          "district": "횡성군",
          "town": "횡성읍",
          "count": 10
        }
      ]
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 특정 월에 방문했던 행정구역 단위 장소 목록을 조회하기 위한 기능입니다.
  • yearMonth를 Query Parameter로 입력하며, 양식은 yyyy-mm입니다. 전체 방문 장소 개수를 조회하고 싶으면 입력하지 않을 수 있습니다.
    • yyyy-mm의 경우
      • 각 장소는 시(city), 군/구(district), 읍/면/동(town) 단위로 제공되며, 한달 기준으로 해당 지역에서 사진이 업로드된 횟수(count)를 기반으로 사용자의 방문량을 나타냅니다.
    • 입력하지 않을 경우
      • 유저가 방문한 도시의 총 개수를 count를 통해 나타냅니다.

앨범 관련

✅ 전체 앨범 목록 월별 조회

  • Endpoint: /api/album/monthly?yearMonth={yearmonth}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • yearMonth (String): 조회하고 싶은 연월 (예: "2025-04")
    • 최초 요청 시 null로 요청
    • 이후 요청 시 응답으로 받은 nextYearMonth 사용
  • Request Body: 없음

✅ Success Response

  • 200 OK – 앨범 목록 조회 성공 (MONTHLY_ALBUM_SUCCESS)

    {
      "code": "MONTHLY_ALBUM_SUCCESS",
      "message": "앨범 목록 조회 성공",
      "data": {
        "albums": [
          {
            "albumId": 1,
            "albumName": "봄 소풍",
            "thumbnailURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/IMG-0001.jpg",
            "createdAt": "2025-04-18T12:00:00",
            "memberProfileImageURL": [
              "https://ongi.s3.ap-northeast-2.amazonaws.com/IMG-0314.jpg",
              "https://ongi.s3.ap-northeast-2.amazonaws.com/IMG-0978.jpg"
            ]
          },
          ...
        ],
        "nextYearMonth": "2025-03"
      }
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 생성한 앨범을 월 단위로 조회하는 기능을 제공합니다.
  • 전체 앨범 목록을 한 번에 불러오지 않고, yearMonth 쿼리 파라미터를 기준으로 월별로 끊어서 데이터를 받아오는 방식입니다.
  • 이 방식은 다음과 같은 무한 스크롤 UI에 최적화되어 있습니다:
    • 클라이언트는 현재 연월(2025-04) 기준으로 API를 호출해 한 달치 앨범 목록을 로드합니다.
    • 사용자가 아래로 스크롤할 때 다음 달(2025-03) 데이터를 추가로 요청하는 식의 월 단위 페이징 흐름을 구성할 수 있습니다.
    • 최대 로딩 사이즈는 24입니다.

✅ 앨범 요약 조회

  • Endpoint: /api/album/{albumId}/summary
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • albumId (Long, 필수): 조회할 앨범의 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 앨범 요약 조회 성공 (ALBUM_SUMMARY_SUCCESS)

    {
      "code": "ALBUM_SUMMARY_SUCCESS",
      "message": "앨범 요약 조회 성공",
      "data": [
        {
          "pictureId": 501,
          "pictureURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/pic-501.jpg",
          "latitude": 37.5441,
          "longitude": 127.0372
        },
        {
          "pictureId": 502,
          "pictureURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/pic-502.jpg",
          "latitude": 35.1586,
          "longitude": 129.1604
        }
      ]
    }
    

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 앨범의 대표 사진들을 요약하여 제공합니다. 각 사진은 위치 정보(위도, 경도)를 포함하며, 사용자가 앨범에 포함된 주요 사진들을 빠르게 확인할 수 있도록 합니다.
  • 이 정보를 활용하여 앨범의 위치 기반 서비스를 제공하거나, 사진들에 대한 미리보기 기능을 제공할 수 있습니다.

✅ 앨범 상세 조회

  • Endpoint: /api/album/{albumId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • albumId (Long, 필수): 조회할 앨범의 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 앨범 조회 성공 (ALBUM_ACCESS_SUCCESS)
{
  "code": "ALBUM_ACCESS_SUCCESS",
  "message": "앨범 조회 성공",
  "data": [
    {
      "title": "제주도 여행",
      "picture": [
        {
          "pictureId": 501,
          "pictureURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/pic-2.jpg",
          "latitude": 35.1586,
          "longitude": 129.1604,
          "tag": "여행",
          "isDullicated": false,
          "isShaky": false,
          "createdAt": "2025-05-04T12:12:12"
        }
      ],
      "cluster" : [
          {
           "clusterId" : 1,
            "clusterName" : "사람-1",
            "representativePicture" : "https://cdn.ongi.today/image1.jpg",
            "bboxX1" : 00, 
            "bboxY1" : 00, 
            "bboxX2" : 00,
            "bboxY2" : 00,
            "clusterPicture" : ["https://cdn.ongi.today/image1.jpg", "https://cdn.ongi.today/image2.jpg"]
          }
      ]
    }
  ]
}

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 앨범의 상세 정보를 조회합니다.
  • 앨범 제목과 함께, 해당 앨범에 포함된 모든 사진의 메타데이터를 포함하여 반환합니다.
  • 사진은 위도/경도, 태그, 흔들림 여부, 중복 여부, 생성 시간 등의 정보를 담고 있습니다.
  • 사진이 인물사진인 경우 클러스터에 포함됩니다. 인물사진은 여러 클러스터에 포함될 수 있습니다. 대표 인물사진은 사진을 확대하기 위한 bbox정보를 함께 반환합니다.

✅ 앨범 생성

  • Endpoint: /api/album
  • HTTP Method: POST

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Request Body

    {
      "albumName": "제주도 여행",
      "concepts" : ["산","바다"],
      "pictureURLs": [
        "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
        "https://ongi.s3.ap-northeast-2.amazonaws.com/2.jpg"
      ]
    }
    

✅ Success Response

  • 200 OK – 앨범 생성 성공 (ALBUM_CREATE_SUCCESS)

    {
      "code": "ALBUM_CREATE_SUCCESS",
      "message": "앨범이 생성되었습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 새로운 앨범을 생성할 때 사용됩니다.
  • 앨범 이름과 대표 이미지 URL, 앨범 컨셉들을 전달하며, 서버는 이를 기반으로 앨범을 생성하고 내부적으로 사진 메타데이터를 저장합니다.
  • 성공 시 별도의 데이터 반환 없이 성공 메시지를 응답합니다.

✅ 앨범에 사진 추가

  • Endpoint: /api/album/{albumId}/picture
  • HTTP Method: POST

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수): 사진을 추가할 대상 앨범 ID
  • Request Body
{
  "pictureURLs": [
    "https://ongi.s3.ap-northeast-2.amazonaws.com/1.jpg",
    "https://ongi.s3.ap-northeast-2.amazonaws.com/2.jpg"
  ]
}

✅ Success Response

  • 200 OK – 사진 추가 성공 (PICTURE_ADD_SUCCESS)
{
  "code": "PICTURE_ADD_SUCCESS",
  "message": "앨범에 사진을 추가했습니다.",
  "data": null
}

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 앨범에 이미지 URL들을 추가하는 기능을 제공합니다.
  • 사용자는 업로드된 이미지들의 URL을 배열로 전달하며, 서버는 이를 기존 앨범에 연결된 사진 목록에 추가합니다.
  • 앨범 멤버가 아닌 사람이 사진을 추가하려고 할 때 403에러를 리턴합니다.

✅ 앨범 이름 수정

  • Endpoint: /api/album/{albumId}
  • HTTP Method: PUT

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수): 이름을 수정할 앨범의 ID
  • Request Body
{
  "albumName": "제주도 여행"
}

✅ Success Response

  • 200 OK – 앨범 이름 수정 성공 (ALBUMNAME_UPDATE_SUCCESS)
{
  "code": "ALBUMNAME_UPDATE_SUCCESS",
  "message": "앨범 이름을 수정했습니다.",
  "data": null
}

⚠️ Error Response

  • 403 Forbidden – 앨범 소유자 아님

    {
      "code": "NOT_ALBUM_OWNER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 기존 앨범의 이름을 수정할 수 있도록 제공됩니다.
  • 수정 대상 앨범은 albumId를 통해 식별하며, 요청 본문에 새 앨범명을 전달합니다.
  • 성공 시 변경 완료 메시지만 반환됩니다.
  • 앨범 소유자가 아닌 경우 403 에러를 반환합니다.

✅ 클러스터 이름 변경

  • Endpoint: /api/album/{albumId}/cluster/{clusterId}
  • HTTP Method: PATCH

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Path Variables

    • albumId (Long): 조회하고자 하는 앨범 아이디
    • clusterId (Long): 변경하고자 하는 클러스터 아이디
  • Request Body

{
  "clusterName": "사람-수정"
}

✅ 앨범 사진 삭제

  • Endpoint: /api/album/{albumId}/image
  • HTTP Method: DELETE

✅ Success Response

  • 200 OK – 클러스터 이름 변경 성공 (CLUSTER_RENAME_SUCCESS)
{
  "code": "CLUSTER_RENAME_SUCCESS",
  "message": "클러스터 이름이 변경되었습니다.",
  "data": null
}

🧩 설계 근거 및 시나리오

  • 이 API는 특정 얼굴 클러스터의 이름을 사용자가 임의로 수정할 수 있도록 지원합니다.
  • 클러스터는 AI 분석 결과로 분류된 사람 그룹을 의미하며, 사용자가 이를 “엄마”, “친구A”처럼 이해하기 쉽게 이름 지정 가능하게 합니다.
  • 접근 권한은 해당 앨범의 멤버인 경우에만 부여됩니다.
  • 변경 시 프론트엔드에서 실시간 반영 가능하도록 200 응답만 반환하며, 별도 데이터는 포함하지 않습니다.

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수): 사진을 삭제할 대상 앨범 ID
  • Request Body
{
  "pictureIds": [501, 502, 503]
}

✅ Success Response

  • 200 OK – 앨범 내 사진 삭제 성공 (PICTURE_DELETE_SUCCESS)
{
  "code": "PICTURE_DELETE_SUCCESS",
  "message": "앨범 내 사진을 삭제했습니다.",
  "data": null
}

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    
  • 404 Not Found – 앨범 또는 사진을 찾을 수 없음

    {
      "code": "ALBUM_NOT_FOUND",
      "message": "사진을 찾을 수 없습니다",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 앨범 내에서 선택된 사진들을 삭제하는 기능을 합니다.
  • 삭제할 사진들의 ID는 배열로 전달되며, albumId를 통해 앨범을 식별합니다.
  • 유효하지 않은 앨범이거나, 요청한 사진이 존재하지 않는 경우 404 에러를 반환합니다.
  • 앨범 구성원이 아닐 경우 403 에러를 반환합니다.

✅ 앨범 삭제

  • Endpoint: /api/album/{albumId}
  • HTTP Method: DELETE

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수): 삭제할 앨범의 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 앨범 삭제 성공 (ALBUM_DELETE_SUCCESS)
{
  "code": "ALBUM_DELETE_SUCCESS",
  "message": "앨범이 삭제되었습니다.",
  "data": null
}

⚠️ Error Response

  • 403 Forbidden – 앨범 소유자 아님

    {
      "code": "NOT_ALBUM_OWNER",
      "message": "앨범 소유자가 아닙니다.",
      "data": null
    }
    
  • 404 Not Found – 앨범을 찾을 수 없음

    {
      "code": "ALBUM_NOT_FOUND",
      "message": "앨범을 찾을 수 없습니다",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 특정 앨범을 완전히 삭제할 때 호출됩니다.
  • 앨범 ID를 통해 삭제할 앨범을 지정하며, 인증된 사용자만 삭제를 요청할 수 있습니다.
  • 앨범 소유자가 아닌 경우 403 에러를 반환합니다.
  • 요청한 앨범이 존재하지 않는 경우에는 404 에러를 반환합니다.

✅ 공동작업자 목록 조회

  • Endpoint: /api/album/{albumId}/members
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • albumId (Long, 필수): 대상 앨범 ID

✅ Success Response

  • 200 OK – 공동작업자 목록 조회 성공 (ALBUM_MEMBER_LIST_SUCCESS)
{
  "code": "ALBUM_MEMBER_LIST_SUCCESS",
  "message": "공동작업자 목록 조회 성공",
  "data": [
    {
      "userId": 1,
      "nickname": "gray (Owner)",
      "profileImageURL": "https://ongi.s3.amazonaws.com/profiles/gray.jpg"
    },
    {
      "userId": 2,
      "nickname": "noah",
      "profileImageURL": "https://ongi.s3.amazonaws.com/profiles/noah.jpg"
    }
  ]
}

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 앨범에 초대된 모든 유저(본인 포함)를 조회합니다.
  • 앨범 유저가 아닌데 조회하려 할 경우 403에러를 반환합니다.

✅ 초대 링크 생성

  • Endpoint: /api/album/{albumId}/invite/link
  • HTTP Method: POST

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수)

✅ Success Response

  • 200 OK – 초대 링크 생성 성공 (INVITE_LINK_CREATED)
{
  "code": "INVITE_LINK_CREATED",
  "message": "초대 링크가 생성되었습니다.",
  "data": {
    "inviteLink": "https://ongi.com/invite?token=eyJhbGciOiJIUzI1NiIsInR5..."
  }
}

⚠️ Error Response

  • 403 Forbidden – 앨범 멤버 아님

    {
      "code": "NOT_ALBUM_MEMBER",
      "message": "앨범 멤버가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 앨범 공동작업자 초대를 위한 JWT 기반 링크를 생성합니다.
  • 생성된 링크는 클립보드 복사 등으로 사용자가 다른 사람에게 전달할 수 있습니다.
  • 토큰은 유효기간과 앨범 ID를 포함하며 DB 저장 없이도 검증 가능하도록 설계됩니다.
  • 앨범 멤버만 초대 링크를 만들 수 있으며, 앨범 멤버가 아닐 경우 403에러를 반환합니다.

✅ 초대 수락

  • Endpoint: /api/album/{albumId}/invite
  • HTTP Method: POST

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수)
  • Request Body
{
  "inviteToken": "eyJhbGciOiJIUzI1NiIsInR5..."
}

✅ Success Response

  • 200 OK – 초대 수락 성공 (ALBUM_INVITE_SUCCESS)
{
  "code": "ALBUM_INVITE_SUCCESS",
  "message": "앨범에 초대되었습니다.",
  "data": {
    "albumId": 5,
    "albumName": "제주 여행"
  }
}

⚠️ Error Response

  • 403 Forbidden – 초대 링크 만료

    {
      "code": "INVITE_LINK_EXPIRED",
      "message": "초대 링크가 만료되었습니다.",
      "data": null
    }
    
  • 403 Forbidden – 초대 링크 인증 불가

    {
      "code": "INVALID_INVITE_LINK",
      "message": "초대 링크가 유효하지 않습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 초대 링크를 받은 사용자가 앨범에 참여할 수 있도록 합니다.
  • 토큰 내 albumId와 URI 내 albumId의 일치 여부를 검증하여 보안을 강화합니다.
  • 초대 수락 시 UserAlbum 테이블에 새로운 데이터가 생성되고 Normal로 권한이 기본 설정됩니다.
  • 초대 링크가 만료되거나 유효하지 않을 경우 403에러를 반환합니다.

✅ 유저의 앨범 접근 권한 확인

  • Endpoint: /api/album/{albumId}/role
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수)

✅ Success Response

  • 200 OK – 접근 권한 있음 (ALBUM_AUTHORIZED)

    {
      "code": "ALBUM_AUTHORIZED",
      "message": "앨범 접근 권한 있음",
      "data": {
        "role": "OWNER"  // 또는 MEMBER
      }
    }
    

⚠️ Error Response

  • 403 Forbidden – 앨범 접근 권한 없음

    {
      "code": "INVALID_ALBUM_ACCESS",
      "message": "앨범 접근 권한이 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 앨범 페이지 접근 전에 권한이 있는지 사전 확인하는 용도로 사용됩니다.
  • UserAlbum 테이블에서 매핑 여부를 조회하며, OWNER/MEMBER 여부도 함께 응답합니다.

✅ 공동작업자 삭제

  • Endpoint: /api/album/{albumId}/members/{userId}
  • HTTP Method: DELETE

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • albumId (Long, 필수)
    • userId (Long, 필수)

✅ Success Response

  • 200 OK – 공동작업자 삭제 성공 (ALBUM_MEMBER_DELETE_SUCCESS)
{
  "code": "ALBUM_MEMBER_DELETE_SUCCESS",
  "message": "공동작업자를 삭제했습니다.",
  "data": null
}

🧩 설계 근거 및 시나리오

  • 이 API는 앨범의 OWNER가 공동작업자를 강제 제거할 수 있도록 제공합니다.
  • UserAlbum에서 해당 유저-앨범 매핑을 삭제하며, 본인 자신은 제거할수 없습니다.

✅ 공동작업자 소유권 위임

  • Endpoint: /api/album/{albumId}/owner
  • HTTP Method: PUT

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수, 반드시 현재 OWNER의 토큰이어야 함)
  • Path Variable
    • albumId (Long, 필수): 소유권을 위임할 앨범 ID
  • Request Body
{
  "newOwnerId": 42
}

✅ Success Response

  • 200 OK – 소유권 위임 성공 (ALBUM_OWNERSHIP_TRANSFER_SUCCESS)
{
  "code": "ALBUM_OWNERSHIP_TRANSFER_SUCCESS",
  "message": "앨범 소유권이 정상적으로 이전되었습니다.",
  "data": {
    "oldOwnerId": 1,
    "newOwnerId": 42
  }
}

⚠️ Error Response 예시

  • 403 Forbidden – 요청자가 OWNER가 아님
{
  "code": "FORBIDDEN",
  "message": "앨범 소유자가 아닙니다.",
  "data": null
}
  • 404 Not Found – 대상 유저가 해당 앨범의 구성원이 아님
{
  "code": "MEMBER_NOT_FOUND",
  "message": "해당 앨범의 공동작업자가 아닙니다.",
  "data": null
}

🧩 설계 근거 및 시나리오

  • 이 API는 앨범의 소유권을 다른 유저에게 이전할 수 있는 기능을 제공합니다.
  • 기존 OWNER가 요청을 보내면, UserAlbum 테이블에서:
    • 본인의 roleNORMAL로 변경하고
    • newOwnerIdroleOWNER로 변경합니다.
  • 이를 통해 OWNER는 유연하게 권한을 넘기고, 새로운 관리자가 생길 수 있습니다.

피드 관련

✅ 피드 등록

  • Endpoint: /api/feed
  • HTTP Method: POST

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Request Body

    {
      "albumId": 1,
      "content": "판교 산책",
      "pictureIds": [101, 102, 103]
    }
    

✅ Success Response

  • 200 OK – 피드 등록 성공 (FEED_CREATE_SUCCESS)

    {
      "code": "FEED_CREATE_SUCCESS",
      "message": "피드가 성공적으로 생성되었습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 400 Bad Request – 사진이 존재하나 같은 앨범에 존재하지 않음

    {
      "code": "PICTURE_NOT_IN_SAME_ALBUM",
      "message": "요청한 사진이 같은 앨범에 존재하지 않습니다.",
      "data": null
    }
    
  • 404 Not Found – 사진이 존재하지 않음

    {
      "code": "PICTURE_NOT_FOUND",
      "message": "해당 사진을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 앨범 내 사진을 선택해 피드를 생성하는 기능을 제공합니다.
  • 본문에는 피드 내용과 함께 어떤 앨범을 기준으로 생성할 것인지(albumId), 어떤 사진들이 포함될 것인지(pictureIds)를 명시합니다.
  • 피드 등록 시 선택한 사진이 실제 앨범에 포함되어 있어야 하며, 없는 사진이 포함될 경우 404 응답을 반환하고, 사진 리소스가 존재하나 같은 앨범에 포함되어있지 않으면 400 응답을 반환합니다.

✅ 피드 상세 조회

  • Endpoint: /api/feed/{feedId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • feedId (Long, 필수): 조회할 피드의 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 피드 상세 조회 성공 (FEED_DETAIL_SUCCESS)

    {
      "code": "FEED_DETAIL_SUCCESS",
      "message": "피드 상세 조회 성공",
      "data": {
        "feedId": 55,
        "content": "제주도 여행하고 싶다.",
        "createdAt": "2025-04-17T15:30:00",
        "updatedAt": "2025-04-17T15:30:00",
        "writer": {
          "userId": 1,
          "nickname": "aaron",
          "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/profiles/user1.jpg"
        },
        "pictures": [
          {
            "pictureId": 501,
            "pictureURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/pic-501.jpg",
            "tag": "바다",
            "latitude": 33.4567,
            "longitude": 126.5678,
            "place": {
              "city": "제주특별자치도",
              "district": "서귀포시",
              "town": "성산읍"
            }
          },
          {
            "pictureId": 502,
            "pictureURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/pic-502.jpg",
            "tag": "쇼핑",
            "latitude": null,
            "longitude": null,
            "place": null}
        ],
        "likeCount": 12,
        "commentCount": 4,
        "isLiked": true}
    }
    
    

⚠️ Error Response

  • 404 Not Found – 피드가 존재하지 않음

    {
      "code": "FEED_NOT_FOUND",
      "message": "존재하지 않는 피드입니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 클라이언트가 특정 피드의 전체 상세 내용을 조회할 수 있도록 제공됩니다.
  • 작성자 정보, 포함된 사진, 위치 정보, 좋아요 수, 댓글 수, 로그인 사용자의 좋아요 여부(isLiked) 등이 포함되어 있습니다.
  • 사진마다 장소 정보가 있을 수도 있고 없을 수도 있으며, 위치 기반 콘텐츠 기능 구현에 활용됩니다.

✅ 피드 전체 조회

  • Endpoint: /api/feed?cursor={lastFeedId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Requset Params
    • lastFeedId (Long): 마지막으로 받은 피드 ID
      • null이라면 최신 피드부터 조회 시작
  • Request Body: 없음

✅ Success Response

  • 200 OK – 피드 목록 조회 성공 (FEED_LIST_SUCCESS)

    {
      "code": "FEED_LIST_SUCCESS",
      "message": "피드 목록 조회 성공",
      "data": {
        "feeds": [
          {
            "feedId": 101,
            "thumbnailURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/thumbnail-101.jpg",
            "createdAt": "2025-04-17T14:00:00",
            "likeCount": 12,
            "isLiked": true,
            "writer": {
              "nickname": "gray",
              "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/profiles/gray.jpg"
            }
          },
          {
            "feedId": 100,
            "thumbnailURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/thumbnail-100.jpg",
            "createdAt": "2025-04-17T13:20:00",
            "likeCount": 5,
            "isLiked": false,
            "writer": {
              "nickname": "noah",
              "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/profiles/yeon.jpg"
            }
          }
        ],
        "hasNext": true,
        "lastFeedId": 100
      }
    }
    

⚠️ Error Response

  • 404 Not Found – 피드 목록 없음

    {
      "code": "FEED_NOT_FOUND",
      "message": "피드 목록을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 무한 스크롤 방식으로 피드 목록을 조회하기 위한 기능을 제공합니다.
  • 클라이언트는 lastFeedId를 기준으로 더 이전 피드를 요청하며, 응답에는 다음 페이지 여부(hasNext)와 함께 마지막 피드 ID가 함께 제공됩니다.
  • 각 피드는 썸네일, 작성자 정보, 좋아요 수 및 로그인 사용자의 좋아요 여부(isLiked) 정보를 포함합니다.
  • 피드 로딩 사이즈 단위는 10입니다.

✅ 팔로우한 유저의 피드 조회

  • Endpoint: /api/feed/follow?cursor={lastFeedId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Requset Params
    • lastFeedId (Long): 마지막으로 받은 피드 ID
      • null이라면 최신 피드부터 조회 시작
  • Request Body: 없음

✅ Success Response

  • 200 OK – 피드 목록 조회 성공 (FEED_LIST_SUCCESS)

    {
      "code": "FEED_LIST_SUCCESS",
      "message": "피드 목록 조회 성공",
      "data": {
        "feeds": [
          {
            "feedId": 101,
            "thumbnailURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/thumbnail-101.jpg",
            "createdAt": "2025-04-17T14:00:00",
            "likeCount": 12,
            "isLiked": true,
            "writer": {
              "nickname": "gray",
              "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/profiles/gray.jpg"
            }
          },
          {
            "feedId": 100,
            "thumbnailURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/thumbnail-100.jpg",
            "createdAt": "2025-04-17T13:20:00",
            "likeCount": 5,
            "isLiked": false,
            "writer": {
              "nickname": "noah",
              "profileImageURL": "https://ongi.s3.ap-northeast-2.amazonaws.com/profiles/yeon.jpg"
            }
          }
        ],
        "hasNext": true,
        "lastFeedId": 100
      }
    }
    

⚠️ Error Response

  • 404 Not Found – 피드를 찾을 수 없음

    {
      "code": "FEED_NOT_FOUND",
      "message": "피드 목록을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 팔로우한 유저들이 작성한 피드만을 최신순으로 페이징 조회하기 위해 사용됩니다.
  • 기본적인 무한스크롤 구조를 따르며, lastFeedId를 기준으로 다음 피드 목록을 요청할 수 있습니다.
  • hasNext가 true일 경우 다음 요청이 가능하며, 클라이언트는 마지막 feedId를 기준으로 추가 로딩을 이어갑니다.
  • 전체 피드 조회와 구분되어 필터링된 피드만 노출됩니다.

✅ 피드 수정

  • Endpoint: /api/feed/{feedId}
  • HTTP Method: PUT

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Path Variable

    • feedId (Long, 필수): 수정할 피드의 ID
  • Request Body

    {
      "albumId": 1,
      "content": "판교 산책 수정",
      "pictureIds": [101, 102, 103]
    }
    

✅ Success Response

  • 200 OK – 피드 수정 성공 (FEED_UPDATE_SUCCESS)

    {
      "code": "FEED_UPDATE_SUCCESS",
      "message": "피드를 수정했습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 404 Not Found – 앨범을 찾을 수 없음

    {
      "code": "ALBUM_NOT_FOUND",
      "message": "앨범을 조회할 수 없습니다.",
      "data": null
    }
    
  • 404 Not Found – 사진을 찾을 수 없음

    {
      "code": "PICTURE_NOT_FOUND",
      "message": "사진을 조회할 수 없습니다.",
      "data": null
    }
    
  • 400 Bad Request – 사진이 존재하나 같은 앨범에 존재하지 않음

    {
      "code": "PICTURE_NOT_IN_SAME_ALBUM",
      "message": "요청한 사진이 같은 앨범에 존재하지 않습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 이미 등록한 피드의 앨범, 내용, 사진 목록을 수정할 수 있도록 제공됩니다.
  • 피드 ID로 기존 피드를 지정하고, 수정할 내용과 연결할 사진 목록을 함께 전송합니다.
  • 앨범이나 사진이 존재하지 않을 경우 404 응답이 반환됩니다.

✅ 피드 삭제

  • Endpoint: /api/feed/{feedId}
  • HTTP Method: DELETE

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • feedId (Long, 필수): 삭제할 피드의 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 피드 삭제 성공 (FEED_DELETE_SUCCESS)

    {
      "code": "FEED_DELETE_SUCCESS",
      "message": "피드를 삭제했습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 404 Not Found – 피드가 존재하지 않음

    {
      "code": "FEED_NOT_FOUND",
      "message": "피드를 찾을 수 없습니다",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 작성한 피드를 완전히 삭제하는 기능을 합니다.
  • feedId를 기준으로 피드를 찾아 삭제하며, 인증된 사용자만 요청할 수 있습니다.


댓글 관련

✅ 전체 댓글 조회

  • Endpoint: /api/feed/{feedId}/comment?cursor={commentId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • feedId (Long, 필수): 댓글을 조회할 피드 ID
    • commentId (Long): 마지막으로 받은 댓글 ID
      • null이면 가장 최신 댓글부터 조회 시작
  • Request Body: 없음

✅ Success Response

  • 200 OK – 댓글 목록 조회 성공 (COMMENT_LIST_SUCCESS)

    {
      "code": "COMMENT_LIST_SUCCESS",
      "message": "피드의 댓글 목록조회 성공했습니다.",
      "data": {
        "content": [
          {
            "commentId": 1001,
            "userId": 501,
            "nickname": "gray",
            "profileImageURL": "https://.../gray.jpg",
            "content": "진짜 멋져요!",
            "createdAt": "2025-04-19T15:50:00",
            "isAuthor": true},
          {
            "commentId": 1000,
            ...
          }
        ],
        "hasNext": true,
        "lastFeedId": 100
        }
    }
    

⚠️ Error Response

  • 404 Not Found – 댓글 목록 없음

    {
      "code": "COMMENT_LIST_NOT_FOUND",
      "message": "댓글 목록을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 피드에 작성된 댓글들을 페이지네이션 방식으로 조회하는 기능을 합니다.
  • 응답에는 총 댓글 수, 전체 페이지 수, 현재 페이지 여부를 포함하여 무한 스크롤 또는 페이지 UI 구성에 활용할 수 있습니다.
  • 각 댓글 항목은 작성자 정보, 댓글 내용, 작성 시각 및 로그인 유저가 작성자인지 여부(isAuthor)까지 포함합니다.

✅ 특정 댓글 조회

  • Endpoint: /api/feed/{feedId}/comment/{commentId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variables
    • feedId (Long, 필수): 피드 ID
    • commentId (Long, 필수): 조회할 댓글 ID
  • Request Body: 없음

✅ Success Response

  • 200 OK – 특정 댓글 조회 성공 (COMMENT_DETAIL_SUCCESS)

    {
      "code": "COMMENT_DETAIL_SUCCESS",
      "message": "댓글 상세 조회에 성공했습니다.",
      "data": {
        "comment": {
          "commentId": 1001,
          "userId": 501,
          "nickname": "gray",
          "profileImageURL": "https://.../gray.jpg",
          "content": "진짜 멋져요!",
          "createdAt": "2025-04-19T15:50:00",
          "isAuthor": true
          }
      }
    }
    

⚠️ Error Response

  • 404 Not Found – 댓글이 존재하지 않음

    {
      "code": "COMMENT_LIST_NOT_FOUND",
      "message": "댓글 목록을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 특정 피드에 작성된 댓글 중 하나를 ID 기준으로 단건 조회하는 기능을 제공합니다.
  • 단일 댓글에는 작성자 정보, 댓글 내용, 작성 시간, 본인 여부(isAuthor)가 포함되어 있습니다.

✅ 댓글 작성

  • Endpoint: /api/feed/{feedId}/comment
  • HTTP Method: POST

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Path Variable

    • feedId (Long, 필수): 댓글을 작성할 피드 ID
  • Request Body

    {
      "content": "진짜 멋져요!"
    }
    

✅ Success Response

  • 200 OK – 댓글 작성 성공 (COMMENT_CREATE_SUCCESS)

    {
      "code": "COMMENT_CREATE_SUCCESS",
      "message": "댓글이 생성되었습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 특정 피드에 댓글을 작성할 때 사용됩니다.
  • 요청 본문에는 댓글의 내용만 전달하면 되고, 성공 시 서버는 댓글을 저장한 뒤 성공 메시지를 응답합니다.

✅ 댓글 수정

  • Endpoint: /api/feed/{feedId}/comment/{commentId}
  • HTTP Method: PUT

📥 Request

  • Request Header

    • Authorization: Bearer <access_token> (필수)
  • Path Variable

    • feedId (Long, 필수): 피드 ID
    • commentId (Long, 필수): 수정할 댓글 ID
  • Request Body

    {
      "content": "진짜 안멋져요!"
    }
    

✅ Success Response

  • 200 OK – 댓글 수정 성공 (COMMENT_UPDATE_SUCCESS)

    {
      "code": "COMMENT_UPDATE_SUCCESS",
      "message": "댓글이 수정되었습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 403 Forbidden – 댓글 작성자가 아님

    {
      "code": "NOT_COMMENT_AUTHOR",
      "message": "댓글 작성자가 아닙니다.",
      "data": null
    }
    
  • 404 Not Found – 댓글이 존재하지 않음

    {
      "code": "COMMENT_LIST_NOT_FOUND",
      "message": "댓글 목록을 조회할 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 작성한 댓글의 내용을 수정할 수 있도록 합니다.
  • 댓글 ID와 피드 ID를 통해 대상을 특정하고, 작성자 본인인지 검증 후 수정이 수행됩니다.
  • 수정 내용은 본문으로 전달되며, 성공 시 확인 메시지를 응답합니다.

✅ 댓글 삭제

  • Endpoint: /api/feed/{feedId}/comment/{commentId}
  • HTTP Method: DELETE

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • feedId (Long, 필수): 피드 ID
    • commentId (Long, 필수): 삭제할 댓글 ID

✅ Success Response

  • 200 OK – 댓글 삭제 성공 (COMMENT_DELETE_SUCCESS)

    {
      "code": "COMMENT_DELETE_SUCCESS",
      "message": "댓글이 삭제되었습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 403 Forbidden – 댓글 작성자가 아님

    {
      "code": "NOT_COMMENT_AUTHOR",
      "message": "댓글 작성자가 아닙니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 작성한 댓글을 삭제할 때 사용됩니다.
  • 요청자는 해당 댓글의 작성자여야 하며, 피드 ID와 댓글 ID를 통해 삭제할 댓글을 정확히 식별합니다.
  • 삭제가 정상적으로 완료되면 성공 메시지를 반환하며, 이후 해당 댓글은 더 이상 조회되지 않습니다.

팔로우 관련

✅ 팔로우

  • Endpoint: /api/follow/{userId}
  • HTTP Method: POST

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Request Params
    • userId (Long, 필수): 팔로우할 대상 유저 ID

✅ Success Response

  • 201 Created – 팔로우 성공 (FOLLOW_SUCCESS)

    json
    복사편집
    {
      "code": "FOLLOW_SUCCESS",
      "message": "팔로우가 완료되었습니다.",
      "data": {
        "followerId": 1001,
        "followingId": 2002,
        "createdAt": "2025-04-24T02:30:12"
      }
    }
    
    

⚠️ Error Response

  • 400 Bad Request – 이미 팔로우한 경우

    {
      "code": "FOLLOW_ALREADY_EXISTS",
      "message": "이미 팔로우한 유저입니다.",
      "data": null
    }
    
  • 404 Not Found – 대상 유저 없음

    {
      "code": "FOLLOW_TARGET_NOT_FOUND",
      "message": "해당 유저를 찾을 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 로그인한 사용자가 다른 유저를 팔로우할 때 사용됩니다.
  • 요청자는 access token을 통해 인증되며, 대상 유저 ID는 Path Variable로 전달됩니다.
  • 중복 팔로우는 허용하지 않으며, 이미 팔로우한 유저에게 요청하면 400 오류를 반환합니다.
  • 팔로우 요청이 성공하면 팔로우 관계가 저장되고, 생성 시각을 함께 응답합니다.

✅ 언팔로우

  • Endpoint: /api/follow/{userId}
  • HTTP Method: DELETE

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • userId (Long, 필수): 언팔로우할 대상 유저 ID

✅ Success Response

  • 200 OK – 언팔로우 성공 (UNFOLLOW_SUCCESS)

    {
      "code": "UNFOLLOW_SUCCESS",
      "message": "팔로우가 완료되었습니다.",
      "data": null
    }
    

⚠️ Error Response

  • 400 Bad Request – 이미 언팔로우 상태

    {
      "code": "ALREADY_UNFOLLOW",
      "message": "이미 언팔로우 되어있습니다",
      "data": null
    }
    
  • 404 Not Found – 대상 유저 없음

    {
      "code": "FOLLOW_TARGET_NOT_FOUND",
      "message": "해당 유저를 찾을 수 없습니다.",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 로그인한 사용자가 기존에 팔로우하고 있던 유저를 언팔로우할 때 사용됩니다.
  • 이미 언팔로우 상태인 경우 400 에러를 반환하여 중복 제거를 방지합니다.
  • 삭제 성공 시 클라이언트는 팔로우 버튼을 다시 활성화할 수 있도록 처리합니다.

✅ 내 팔로잉 리스트 조회

  • Endpoint: /api/follow/following?cursor={followerId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Query Parameter
    • cursor (Long, optional): 마지막으로 받은 userId.

      페이징 처리를 위한 커서 값. null 또는 생략 시 최신부터 조회


✅ Success Response

  • 200 OK – 팔로잉 목록 조회 성공 (FOLLOWING_LIST_SUCCESS)

    {
      "code": "FOLLOWING_LIST_SUCCESS",
      "message": "팔로잉 목록 조회에 성공했습니다.",
      "data": {
        "followings": [
          {
            "userId": 2002,
            "nickname": "친구1",
            "profileImageUrl": "https://s3.amazonaws.com/.../profile1.png",
            "createdAt": "2025-04-20T01:10:00"
          },
          {
            "userId": 2003,
            "nickname": "친구2",
            "profileImageUrl": "https://s3.amazonaws.com/.../profile2.png",
            "createdAt": "2025-04-18T14:22:11"
          }
        ],
        "hasNext": true,
        "nextCursor": 2003
      }
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 로그인한 사용자가 현재 팔로우하고 있는 팔로잉 리스트를 무한스크롤 방식으로 조회하는 기능입니다.
  • cursor를 기준으로 다음 목록을 요청할 수 있으며, 응답에는 hasNextnextCursor가 함께 제공됩니다. 로딩 기본사이즈는 20입니다.
  • 닉네임, 프로필 이미지, 팔로우한 시간(createdAt) 등 기본 사용자 정보가 포함됩니다.

✅ 내 팔로워 리스트 조회

  • Endpoint: /api/follow/follower?cursor={followerId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Query Parameter
    • cursor (Long, optional): 마지막으로 받은 userId.

      페이징 처리를 위한 커서 값. 생략 또는 null이면 첫 페이지 조회


✅ Success Response

  • 200 OK – 팔로워 목록 조회 성공 (FOLLOWERS_LIST_SUCCESS)

    {
      "code": "FOLLOWERS_LIST_SUCCESS",
      "message": "팔로워 목록 조회에 성공했습니다.",
      "data": {
        "followers": [
          {
            "userId": 2002,
            "nickname": "친구1",
            "profileImageUrl": "https://s3.amazonaws.com/.../profile1.png",
            "createdAt": "2025-04-20T01:10:00"
          },
          {
            "userId": 2003,
            "nickname": "친구2",
            "profileImageUrl": "https://s3.amazonaws.com/.../profile2.png",
            "createdAt": "2025-04-18T14:22:11"
          }
        ],
        "hasNext": true,
        "nextCursor": 2003
      }
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 로그인한 사용자를 팔로우한 팔로워 목록을 커서 기반 무한스크롤로 조회합니다.
  • cursor는 마지막으로 조회된 userId 기준이며, hasNextnextCursor로 프론트가 다음 페이지 요청 가능 여부를 판단할 수 있습니다. 기본 로딩 사이즈는 20입니다.
  • 팔로워의 기본 정보(닉네임, 프로필, 팔로우 시점 등)가 함께 제공됩니다.

알림 관련

✅ 알림 목록 조회

  • Endpoint: /api/notification?cursor={lastNotificationId}
  • HTTP Method: GET

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Query Parameter
    • lastNotificationId (Long): 마지막으로 받은 알림 ID
      • null이면 가장 최신 알림부터 조회 시작

✅ Success Response

  • 200 OK – 알림 목록 조회 성공 (NOTIFICATION_LIST_SUCCESS)

    {
      "code": "NOTIFICATION_LIST_SUCCESS",
      "message": "알림 목록을 불러왔습니다.",
      "data": {
        "content": [
          {
            "notificationId": 101,
            "type": "FEED_COMMENT",
            "resourceId": 555,
            "message": "gray님이 댓글을 남겼습니다.",
            "createdAt": "2025-04-19T15:56:00"
          }
        ],
        "page": 0,
        "size": 10,
        "totalElements": 25,
        "totalPages": 3,
        "last": false}
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자의 알림 목록을 최신순으로 조회하는 기능을 제공합니다.
  • lastNotificationId를 기준으로 이전 알림들을 불러오는 무한스크롤 방식에 적합하게 설계되어 있습니다.
  • 각 알림에는 알림 유형(type), 관련 리소스 ID(resourceId), 메시지, 생성 일시 등이 포함되어 있습니다.

✅ 알림 읽음 처리

  • Endpoint: /api/notification/{notificationId}/status
  • HTTP Method: POST

📥 Request

  • Request Header
    • Authorization: Bearer <access_token> (필수)
  • Path Variable
    • notificationId (Long, 필수): 읽음 처리할 알림 ID

✅ Success Response

  • 200 OK – 알림 읽음 처리 성공 (NOTIFICATION_READ_SUCCESS)

    {
      "code": "NOTIFICATION_READ_SUCCESS",
      "message": "알림을 읽었습니다",
      "data": null
    }
    

🧩 설계 근거 및 시나리오

  • 이 API는 사용자가 받은 특정 알림을 읽음 처리하기 위한 기능입니다.
  • 읽음 처리된 알림은 UI 상에서 읽은 표시(예: bold 제거, 뱃지 감소 등)로 반영할 수 있으며, 서버에서도 상태 관리가 가능합니다.