Skip to content

wijihoon/securities-real-time-rank

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KAKAOPAY RAIN MONEY API


카카오페이증권 과제

기간 : ~ 2022.09.29 23:59까지

요구사항

  1. 서비스 제공에 필요한 RESTful API 를 구현합니다.
  2. 실시간 데이터의 변동을 위해 데이터가 랜덤으로 변경되는 API를 추가로 개발해 주시기 바랍니다.
  3. Application이 로딩될 때 기본 데이터가 DB에 적재하도록 합니다. (주식 종목에 대한 정보는 첨부된 데이터를 참고하시면 됩니다.)
  4. 데이터 테이블 구조는 효율적인 방식으로 스스로 설계해 주시면 됩니다.
  5. 각 기능 및 제약사항에 대한 단위테스트를 작성합니다.

제약사항

  1. 설계 내용과 이유, 핵심 문제해결 전략 및 분석한 내용을 작성하여 “readme.md” 파일에 첨부 해주세요.
  2. 개발은 SpringBoot 와 JAVA를 사용해서 구현하시기 바랍니다.
  3. API의 HTTP Method들은 자유롭게 선택하시면 됩니다. (GET, POST, DELETE, PUT, PATCH)
  4. 에러응답, 에러코드는 자유롭게 정의해주세요.
  5. 단위 테스트를 작성하세요.

평가항목

  1. 프로젝트 구성방법 및 관련된 시스템 아키텍쳐 설계방법이 적절한가?
  2. 요구사항을 잘 이해하고 구현하였는가?
  3. 작성한 어플리케이션 코드의 가독성이 좋고 의도가 명확한가?
  4. 작성한 테스트코드는 적절한 범위의 테스트를 수행하고 있는가?
  5. 어플리케이션은 다량의 트래픽에도 무리가 없도록 효율적으로 작성되었는가?

🏃‍♂️ 목차


🏃‍♂️ 개발 환경

  • JDK 11
  • Spring Boot 2.5.3
  • STS-4-4.16.0.RELEASE
  • JPA
  • H2
  • Redis
  • Maven
  • Junit

🏃‍♂️ ER 다이어그램

kakaopay_server_ERD


🏃‍♂️ API 명세

HTTP 상태 코드

상태코드 싱태 설명
200 성공 정상 응답
201 성공 정상적으로 생성
400 실패 잘못된 요청
404 실패 리소스를 찾을 수 없음
500 실패 시스템 에러

에러 코드

code 설명 HTTP상태코드
000 예상치 못한 오류가 발생하였습니다. 500
101 서버 내부에서 처리 중에 에러가 발생했습니다. 400
102 파라미터 확인부탁드립니다. 400
103 서비스 점검 중입니다. 공지사항을 확인해주세요. 400
104 헤더 정보 확인부탁드립니다. 400

Response

HTTP/1.1 400 Bad Request  
{
  "code": 101,
  "msg":"서버 내부에서 처리 중에 에러가 발생했습니다."
}

모든 주제 랭킹 조회 API

  • 이 API는 카카오페이증권 모든 주제 Top5를 조회하는 API입니다.
  • 주문 조회 API를 사용해 개별 주문의 상세 정보를 조회합니다. 앱 어드민 키를 헤더에 담아 POST로 요청합니다. 아래 두 가지 예제 중 어느 방법을 사용해도 결과는 같습니다. 요청이 성공하면 응답은 바디에 JSON 객체로 주문 상세 정보를 포함합니다.

Response

Name Type Descrption
viewALot ViewALot[] 많이 본 상세
riseALot RiseALot[] 많이 오른 상세
dropALot DropALot[] 많이 내린 상세
volumeHigh VolumeHigh[] 많이 보유한 상세

ViewALot(JSON), RiseALot(JSON), DropALot(JSON), VolumeHigh(JSON)

Name Type Descrption
code String 상품코드
codeNm String 상품코드명
rank BigDecimal 순위
price BigDecimal 가격
percent Double 백분율

Sample

Request

curl -v -X GET "http://localhost:8080/api/rank"

Response

HTTP/1.1 200 OK
Content-type: application/json;charset=UTF-8
{
    "dropALot": [
        {
            "code": "010140",
            "codeName": "삼성중공업",
            "rank": 1.0,
            "price": 5063.00,
            "percent": -15.4800
        },
        {
            "code": "003410",
            "codeName": "쌍용C&E",
            "rank": 2.0,
            "price": 6218.00,
            "percent": -11.5600
        },
        {
            "code": "006800",
            "codeName": "미래에셋증권",
            "rank": 3.0,
            "price": 6169.00,
            "percent": -8.3400
        },
        {
            "code": "024110",
            "codeName": "기업은행",
            "rank": 4.0,
            "price": 9006.00,
            "percent": -7.0600
        },
        {
            "code": "034220",
            "codeName": "LG디스플레이",
            "rank": 5.0,
            "price": 15524.00,
            "percent": -4.4700
        }
    ],
    "riseALot": [
        {
            "code": "008560",
            "codeName": "메리츠증권",
            "rank": 1.0,
            "price": 5614.00,
            "percent": 13.8700
        },
        {
            "code": "028670",
            "codeName": "팬오션",
            "rank": 2.0,
            "price": 6179.00,
            "percent": 11.9300
        },
        {
            "code": "018880",
            "codeName": "한온시스템",
            "rank": 3.0,
            "price": 11192.00,
            "percent": 5.5800
        },
        {
            "code": "316140",
            "codeName": "우리금융지주",
            "rank": 4.0,
            "price": 12723.00,
            "percent": 4.2800
        },
        {
            "code": "015760",
            "codeName": "한국전력",
            "rank": 5.0,
            "price": 22295.00,
            "percent": 3.4500
        }
    ],
    "viewALot": [
        {
            "code": "007070",
            "codeName": "GS리테일",
            "rank": 1.0,
            "price": 24854.00,
            "percent": -2.9200
        },
        {
            "code": "259960",
            "codeName": "크래프톤",
            "rank": 2.0,
            "price": 257137.00,
            "percent": -0.3400
        },
        {
            "code": "017670",
            "codeName": "SK텔레콤",
            "rank": 3.0,
            "price": 51944.00,
            "percent": 1.4500
        },
        {
            "code": "096770",
            "codeName": "SK이노베이션",
            "rank": 4.0,
            "price": 209936.00,
            "percent": -0.2700
        },
        {
            "code": "047810",
            "codeName": "한국항공우주",
            "rank": 5.0,
            "price": 56536.00,
            "percent": 0.7700
        }
    ],
    "volumeHigh": [
        {
            "code": "055550",
            "codeName": "신한지주",
            "rank": 1.0,
            "price": 36084.00,
            "percent": 1.6400
        },
        {
            "code": "066570",
            "codeName": "LG전자",
            "rank": 2.0,
            "price": 102508.00,
            "percent": 0.4900
        },
        {
            "code": "047810",
            "codeName": "한국항공우주",
            "rank": 3.0,
            "price": 56536.00,
            "percent": 0.7700
        },
        {
            "code": "105560",
            "codeName": "KB금융",
            "rank": 4.0,
            "price": 50214.00,
            "percent": -0.9600
        },
        {
            "code": "139480",
            "codeName": "이마트",
            "rank": 5.0,
            "price": 105463.00,
            "percent": 0.4400
        }
    ]
}

주제별 랭킹 조회 API

  • 이 API는 카카오페이증권 주제별 최대 Top100을 조회하는 API입니다.
  • 주문 조회 API를 사용해 개별 주문의 상세 정보를 조회합니다. 앱 어드민 키를 헤더에 담아 POST로 요청합니다. 아래 두 가지 예제 중 어느 방법을 사용해도 결과는 같습니다. 요청이 성공하면 응답은 바디에 JSON 객체로 주문 상세 정보를 포함합니다.

Request

Name Type Descrption
id int 0 = 많이 본, 1 = 많이 오른, 2 = 많이 내린, 3 = 많이 보유한
paging int default = 20, max = 100

Response

Name Type Descrption
viewALot ViewALot[] 많이 본 상세
riseALot RiseALot[] 많이 오른 상세
dropALot DropALot[] 많이 내린 상세
volumeHigh VolumeHigh[] 많이 보유한 상세

ViewALot(JSON), RiseALot(JSON), DropALot(JSON), VolumeHigh(JSON)

Name Type Descrption
code String 상품코드
codeNm String 상품코드명
rank BigDecimal 순위
price BigDecimal 가격
percent Double 백분율

Sample

Request

curl -v -X GET "http://localhost:8080/api/rank/{id}"

Response

HTTP/1.1 200 OK
Content-type: application/json;charset=UTF-8
{
    "riseALot": [
        {
            "code": "008560",
            "codeName": "메리츠증권",
            "rank": 1.0,
            "price": 5614.00,
            "percent": 13.8700
        },
        {
            "code": "028670",
            "codeName": "팬오션",
            "rank": 2.0,
            "price": 6179.00,
            "percent": 11.9300
        },
        {
            "code": "018880",
            "codeName": "한온시스템",
            "rank": 3.0,
            "price": 11192.00,
            "percent": 5.5800
        },
        {
            "code": "316140",
            "codeName": "우리금융지주",
            "rank": 4.0,
            "price": 12723.00,
            "percent": 4.2800
        },
        {
            "code": "015760",
            "codeName": "한국전력",
            "rank": 5.0,
            "price": 22295.00,
            "percent": 3.4500
        },
        {
            "code": "026960",
            "codeName": "동서",
            "rank": 6.0,
            "price": 26514.00,
            "percent": 3.3600
        },
        {
            "code": "371460",
            "codeName": "TIGER 차이나전기차SOLACTIVE",
            "rank": 7.0,
            "price": 17138.00,
            "percent": 3.2400
        },
        {
            "code": "138040",
            "codeName": "메리츠금융지주",
            "rank": 8.0,
            "price": 30696.00,
            "percent": 2.1400
        },
        {
            "code": "032640",
            "codeName": "LG유플러스",
            "rank": 9.0,
            "price": 12569.00,
            "percent": 1.7700
        },
        {
            "code": "006360",
            "codeName": "GS건설",
            "rank": 10.0,
            "price": 32058.00,
            "percent": 1.7700
        },
        {
            "code": "055550",
            "codeName": "신한지주",
            "rank": 11.0,
            "price": 36084.00,
            "percent": 1.6400
        },
        {
            "code": "005830",
            "codeName": "DB손해보험",
            "rank": 12.0,
            "price": 63345.00,
            "percent": 1.5100
        },
        {
            "code": "004990",
            "codeName": "롯데지주",
            "rank": 13.0,
            "price": 39468.00,
            "percent": 1.4600
        },
        {
            "code": "017670",
            "codeName": "SK텔레콤",
            "rank": 14.0,
            "price": 51944.00,
            "percent": 1.4500
        },
        {
            "code": "036460",
            "codeName": "한국가스공사",
            "rank": 15.0,
            "price": 42288.00,
            "percent": 1.4100
        },
        {
            "code": "086790",
            "codeName": "하나금융지주",
            "rank": 16.0,
            "price": 39037.00,
            "percent": 1.3900
        },
        {
            "code": "030200",
            "codeName": "KT",
            "rank": 17.0,
            "price": 38521.00,
            "percent": 1.3700
        },
        {
            "code": "000060",
            "codeName": "메리츠화재",
            "rank": 18.0,
            "price": 38649.00,
            "percent": 1.3000
        },
        {
            "code": "008770",
            "codeName": "호텔신라",
            "rank": 19.0,
            "price": 73136.00,
            "percent": 1.2900
        },
        {
            "code": "047050",
            "codeName": "포스코인터내셔널",
            "rank": 20.0,
            "price": 25445.00,
            "percent": 1.1700
        }
    ]
}

순위 랜덤 변경 API

  • 이 API는 카카오페이증권 모든 주제를 랜덤하게 변경하는 API입니다.
  • 주문 조회 API를 사용해 개별 주문의 상세 정보를 조회합니다. 앱 어드민 키를 헤더에 담아 POST로 요청합니다. 아래 두 가지 예제 중 어느 방법을 사용해도 결과는 같습니다. 요청이 성공하면 응답은 바디에 JSON 객체로 주문 상세 정보를 포함합니다.

Response

Name Type Descrption
code String 코드
message String 메시지

Sample

Request

curl -v -X POST "http://localhost:8080/api/randomRank"

Response

HTTP/1.1 200 OK
Content-type: application/json;charset=UTF-8
{
    
    "code": 201,
    "message": "success"
}

🏃‍♂️ 핵심 문제 해결 전략


주제별 랭킹 조회 API

  • 요구사항에는 없는 내용이지만 현재 상용 뿌리기 서비스에는 있는 뿌릴 인원수 최대값을 채팅방 사용자 수 - 1(본인) 보다 크지 않도록 구현. 불필요하게 뿌릴 인원수를 많이 설정하여 요청자 지갑으로 환불하는 로직을 호출해야하기 때문에 서비스 과부하 가능성 있기 때문(프론트에서 막아도 됨)
  • 뿌리기 토큰을 랜덤 3자리로 생성할 때 random() 대신randomAlphanumeric() 으로 생성하여 인코딩 오류 방지, 또한 DB 데이터와 중복 체크 필수, 또한 다른 곳에서도 사용할 확장성 고려하여 공통 함수로 분리
  • 중복될 경우나 내부 오류시 지정해놓은 횟수만큼 반복 생성하는데, 현재는 3회로 지정하였지만 추후 뿌릴 인원(count)에 맞춰서 유동적으로 가져가는 것도 고민중.

순위 랜덤 변경 API

  • 돈이 오고가는 거래이므로 로직 중에 오류나면 생성한 레코드 롤백하는 @Transaction 어노테이션 사용
  • 뿌린 금액이 DB에 오름차순으로 저장되어 있기 때문에 뿌린 금액 받기 기능 호출시 한번 더 랜덤 정렬 시행하여 '랜덤'기능 충실

데이터 모델링 관련

  • KP_TB_RAIN_MONEY의 FK를 KP_TB_ROOM_USER의 복합키로 할지, 각각의 PK로 할지 고민하다가 복합키로 결정하였으나 조회문이 복잡해지는 단점 생.
  • TOKEN 필드의 데이터크기를 3자리로 잡았는데, 추후 확장성을 고려해 더 넉넉하게 잡았어도 좋았겠다는 생각. 서비스가 확장되면 인원이 늘어나고 3자리수로 유니크한 문자가 한계가 있기 때문
  • PK Java에서는 Long인데 데이터 타입 Unsigned int로 할지, bigint로 할지 고민했다가 Java에서는 기본적으로 unsigned type을 지원하지 않아서 방법은 있겠으나 시간을 뺏길 것 같아서 bigint 사용