# 같이 공유할 사항 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 - 최적의 가중치 선정 과정 - 그 외에 고민했던 내용 - 프로젝트 내에서 고민 - 좋은 코드를 위해선 - 좋은 추천이란 - 성능 개선 부분 - 팀원들과 서버로 협업하는 과정에서 했던 고민