# 같이 공유할 사항 api
###### tags: `공유 사항`
### error response
```
{
"code": -20,
"status": 401,
"message": "user password not match"
}
```
### status: int, error code: int, message: String 순서
// Common
INVALID_INPUT_VALUE(400,-1, "Invalid Input value"),
METHOD_NOT_ALLOWED(405, -2, "Invalid Http method"),
ENTITY_NOT_FOUND(400, -3, "Entity Not Found"),
INTERNAL_SERVER_ERROR(500, -99, "Server Error"),
// User
USER_EMAIL_NOT_VERIFIED(400, -10, "user email is not admitted"),
USER_NEED_TO_CHANGE_PASSWORD(400,-11, "user have to change password"),
USER_NOT_FOUND(404, -12, "user is not found"),
REFRESH_TOKEN_NOT_VALID(400,-13, "refresh token is not valid"),
REFRESH_TOKEN_EXPIRED(400, -14, "refresh token is expired"),
EMAIL_HASH_NOT_VALID(400, -15, "email hash value is not valid"),
USER_TOKEN_NOT_VALID(400, -16, "token is not valid"),
USER_ACCESS_DENIED(400, -17, "user is not acceptable"),
DUPLICATED_USER_EMAIL(409, -18, "duplicated email"),
USER_EMAIL_NOT_FOUND(404, -19, "user email not found"),
USER_PASSWORD_NOT_MATCH(401, -20, "user password not match"),
// GATEWAY FILTER - TOKEN
USER_TOKEN_EXPIRED(400, -21, "token is expired"),
USER_TOKEN_EMPTY(404, -22, "token is empty")
// Product
INVALID_SIZE_FOR_PRODUCT(400, -50, "product size is not valid"),
CANNOT_TRADE_MYSELF(409, -51, "you can not buy or sell your item"),
USER_DOES_NOT_MATCH_TRADE_UPDATE(401, -52, "user did not create this trade")
### 거래 관련 변수명
var changePercentage: Float, - 직전 거래에 비해 변동 수치 퍼센트
var changeValue: Int, - 직전 거래에 비해 변동 가격
var highestBid: Int, - 즉시 판매가
var lastSalePrice: Int, - 최근 거래가
var lowestAsk: Int, - 즉시 구매가
var pricePremium: Int, - 최근 거래가에서 원래 발매 가격을 뺀 금액
var pricePremiumPercentage: Float, - 발매가에서 최근 가격까지 얼마나 올랐는지
var totalSale: Int - 총 판매량
### 상품 리스트 하나
[X] val id: Long?,
[X] val originalName: String,
[X] val translatedName: String,
[X] val originalPrice: Int,
[X] val gender: Boolean,
[X] val category: String,
[X] val color: String,
[X] val styleCode: String, // 모델 번호
[X] val wishCnt: Int,
[X] val brandId: Long?,
[] val collectionId: Long?,
[X] val brandName: String,
[X] val backgroundColor: String,
[X] val imageUrls: [String],
[ ] val sizes: [String],
[ ] val releasedDate: LocalDate?,
[ ] val highestBid: Int,
[ ] val totalSale: Int,
[ ] (로그인시) val wishList: String?
```
[
{
"product":
"backgroundColor": "string",
"brandName": "string",
"category": "string",
"color": "string",
"gender": "string",
"id": 0,
"imageUrls": "string",
"originalName": "string",
"originalPrice": 0,
"releasedDate": "string",
"sizes": "string",
"styleCode": "string",
"totalSale": 0,
"translatedName": "string",
"wishCnt": 0,
"wishList": "230,240,270",
"lowestAsk": 0
}
]
```
요청 두 개 날리기-> 상품에 대한 정보(상품 서버), 거래에 대한 정보(거래 서버)
### 상품 디테일
상품의 사이즈별 거래 값(가격 및 변동 지수) + 상품 디테일 정보 + 유저 위시 정보
```
{
"product": {
"id": 1,
"originalName": "Nike Dunk Low Retro Black",
"translatedName": "나이키 덩크 로우 레트로 블랙",
"originalPrice": 129000,
"gender": "man",
"category": "sneakers",
"color": "white/black",
"styleCode": "DD1391-100",
"wishCnt": 0,
"brandName": "nike",
"backgroundColor": "#f4f4f4",
"imageUrls": "[\"https://kream-phinf.pstatic.net/MjAyMTA3MjhfMjIg/MDAxNjI3NDQxMDA1NjE5.HOgIYywGZaaBJDqUzx2OnX9HAxoOWPvuWHqUn_LZGcgg.VYIuOfA5_GgjBGRowv6dmQuAOPtUvmAxbGpOyUCOCtYg.PNG/p_9d8ed1a74d2540ab9842e63363607bf4.png\", \"https://kream-phinf.pstatic.net/MjAyMTA3MjhfMTk2/MDAxNjI3NDQxMDEwNTc1.OVWeJtFIWhzmfjmKBH7islcWu25BA5kRgCum0NefxiEg.3-WlGTrUGQIqwMLUquLu-qbwAm4MAazH2vAwDr9DB8sg.PNG/p_21b22bba768a49378b071d15fe3671c7.png\", \"https://kream-phinf.pstatic.net/MjAyMTA3MjhfMjQx/MDAxNjI3NDQxMDEyMjA2.DcysBFreA7tuLaKgU7UyPWct_NH87Ad9ktvGmEmaXjUg.VFp5d9BX5YPB-h6fGruYOUDXGrz_UPXrJWnPANfhhJAg.PNG/p_8d86fe659c3542b2aaafa40a7a0048c1.png\"]",
"sizes": "[\"230\", \"235(US 4.5)\", \"235(US 5)\", \"240(US 5.5)\", \"240(US 6)\", \"245\", \"250\", \"255\", \"260\", \"265\", \"270\"]",
"releasedDate": "2021-01-14",
"totalSale": 0,
"wishList": "230,240,270",
"lowestAsk": 180000 // 전체 사이즈에서 가장 저렴한 판매 가격
},
"pricesBySize": [
{
"size": "230",
"lowestAsk": 200000
},
{
"size": "245",
"lowestAsk": 180000
},
{
"size": "250",
"lowestAsk": 180000
}
],
"lowestAsk": 180000, // 현재 선택한 사이즈에서 가장 저렴한 판매 가격
"highestBid": 190000,
"changePercentage": null,
"changeValue": null,
"lastSalePrice": null,
"pricePremium": null,
"pricePremiumPercentage": null
}
```
### 필터
컬렉션(객체 Object List), 브랜드(Object List), 성별(Constant List), 카테고리(Constant List)
```
{
"brands": [
{
"id": 0,
"logoImageUrl": "string",
"name": "string"
}
],
"categories": [
"string"
],
"collections": [
{
"brand": {
"id": 0,
"logoImageUrl": "string",
"name": "string"
},
"id": 0,
"name": "string"
}
],
"gender": [
"string"
]
}
```
1. product wishList, lowestAsk 밖으로 빼기
```
struct HomeData {
let adImageUrls: [String]
let sections: [SectionInfo]
}
struct SectionInfo {
let header: String
let detail: String
let imageUrl: String
let products: [Product]
}
```
sort 종류
```
lowest_ask - 구매 낮은 순 판매
highest_bid - 가능한 상품 높은 순
premium_price - 발매가에 비해 오른 가격 순
total_sale - 총 판매수
released_date - 발매일 최신 순
```
카테고리 종류
```
의류 : streetwear
스니커즈: sneakers
라이프: life
테크: electronics
악세서리: accessories
가방: premium-bags
```
일별 가격
```
{
"oneMonth": [
{
"date": "string",
"price": 0
}
],
"oneYear": [
{
"date": "2022-01-27",
"price": 0
}
],
"sixMonth": [
{
"date": "2022-01-27",
"price": 0
}
],
"threeMonth": [
{
"date": "2022-01-27",
"price": 0
}
],
"total": [
{
"date": "2022-01-27",
"price": 0
}
]
}
```
User Status
```
0 - 가입 신청 완료
1 - 비밀번호를 반드시 변경해야 하는 회원
2 - 이메일 인증한 회원
3 - 삭제된 회원
```
Table of Conents
- Index
- Server 기능 소개
- 설계 및 구현
- 트러블 슈팅 및 대응 방법
- 그 외에 고민한 내용
- Server 기능 소개
- Directory
- 프로젝트 공통 특징
- User server
- Product server
- Log server
- Recommendation
- 설계 및 구현
- 프로젝트 구현 사항 및 기술 선정이유
- 코틀린
- 스프링
- JPA
- Mysql
- Mongodb
- Redis
- MSA
- 스프링 클라우드 프로젝트
- 개인화 추천
- 상품 데이터 제작
- 유저 데이터 제작
- 어떻게 하면 진짜 비지니스에서 사용 가능한 그럴듯한 유저데이터를 만들 수 있을까?
- 추천 알고리즘
- CF
- 유사도 선정 과정
- 최적의 이웃 선정 과정
- CBF
- 유사도 선정 과정
- Hybrid
- 최적의 가중치 선정 과정
- 그 외에 고민했던 내용
- 프로젝트 내에서 고민
- 좋은 코드를 위해선
- 좋은 추천이란
- 성능 개선 부분
- 팀원들과 서버로 협업하는 과정에서 했던 고민