- JAVA 17
- Spring Boot 3.x.
- MySQL
- 요구사항을 issue에 기록하고 pr 단위로 작업을 진행했습니다.
- Git clone (https://github.com/jooooonj/aswemake_Project.git)
- application-secret.yml.default -> application-secret.yml 파일명 변경
- application-secret.yml 환경변수 직접 기입
- 로컬 MySQL 접속 후 데이터베이스 생성
- 실행
- 데이터베이스 생성 SQL
DROP
DATABASE IF EXISTS ${DATABASE_NAME};
CREATE
DATABASE ${DATABASE_NAME};
USE
${DATABASE_NAME};
${DATABASE_HOST} : 데이터베이스 호스트 주소
${DATABASE_PORT} : 데이터베이스 포트 번호
${DATABASE_NAME} : 데이터베이스 이름
${DATABASE_USERNAME} : 데이터베이스 사용자 이름
${DATABASE_PASSWORD} : 데이트베이스 비밀번호
${JWT_SECRET_KEY} : JWT 토큰 서명에 사용되는 비밀 키
${MART_ADMIN_EMAIL} : 관리자 계정 (이메일 형식 @포함)
${MART_ADMIN_PASSWORD} : 관리자 계정 비밀번호 (8자리 이상)
- Git clone (https://github.com/jooooonj/aswemake_Project.git)
- application-secret.yml.default -> application-secret.yml 파일명 변경
- 프로젝트 하위 경로 .env 파일 생성 후 양식에 맞게 기입
- jar 빌드 (./gradlew clean build)
- 도커 실행 (docker compose up -d)
MYSQL_CONTAINER_NAME={사용자지정 - MYSQL 컨테이너 이름}
MYSQL_DATABASE={사용자지정 - MYSQL 데이터베이스 이름}
MYSQL_ROOT_PASSWORD={사용자지정 - MYSQL root계정 비밀번호}
JWT_SECRET_KEY={사용자지정 - JWT 토큰 서명에 사용되는 비밀 키}
MART_ADMIN_EMAIL={사용자지정 - 마트계정 이메일 (이메일 형식 @ 필수)}
MART_ADMIN_PASSWORD={사용자지정 - 마트계정 비밀번호(8자리 이상)}
- id (PK)
- password
- roleType
- MART, MEMBER
- created_date
- modified_date
- id (PK)
- product_name
- price
- product_snapshot_id (FK)
- 일대일 관계 : 상품 스냅샷 (product_snapshot)과 연결
- created_date
- modified_date
- id (PK)
- productId
- product_name
- price
- fromDate
- toDate
- id (PK)
- member_id (FK)
- 다대일 관계 : 회원(member)과 연결
- coupon_id (FK)
- 일대일 관계 : 쿠폰(discount_coupon)과 연결
- total_price
- delivery_fee
- created_date
- modified_date
- id (PK)
- order_id (FK)
- 다대일 관계 : 주문(orders)과 연결
- product_id (FK)
- 다대일 관계 : 상품(productSnapshot)과 연결
- coupon_id (FK)
- 일대일 관계 : 쿠폰(discount_coupon)과 연결
- quantity
- order_item_price
- coupon_id (PK)
- coupon_type
- FIXED, PERCENTAGE
- coupon_apply_scope
- ORDER_ALL, SPECIFIC_PRODUCT
- coupon_code (UUID)
- created_date
- modified_date
- coupon_id (PK,FK)
- fixed_discount_amount
- coupon_id (PK,FK)
- discount_percentage
- 초기 데이터 (2개)
- 환경변수에 기입한 관리자 계정 (마트권한)
- 이메일 : [email protected], 비밀번호 : 12345678 (회원권한)
-
엔드포인트: POST /api/v1/member/join
-
Request Body: 사용자 정보를 담은 요청 데이터
- email (문자열): 사용자의 이메일 주소 (반드시 '@' 포함)
- password (문자열): 사용자의 비밀번호 (최소 8자리 이상)
-
Response: 생성된 회원의 ID
- Method: POST
- URL: http://localhost:8080/api/v1/member/join
- Headers: Content-Type: application/json
- Body:{ "email": "[email protected]", "password": "123456789" }
- Status: 201 Created
- Body : 생성된 회원의 ID
- 이메일과 비밀번호로 계정을 생성합니다.
- 관리자 계정은 초기에 자동 생성됩니다.
- 관리자 계정과 같은 이메일은 사용이 불가능합니다.
- 엔드포인트: POST /api/v1/member/login
- Request Body: 사용자 정보를 담은 요청 데이터
- email (문자열): 가입된 사용자의 이메일 주소 (반드시 '@' 포함)
- password (문자열): 가입된 사용자의 비밀번호 (최소 8자리 이상)
- Response: JWT 토큰
- Method: POST
- URL: http://localhost:8080/api/v1/member/login
- Headers:
- Content-Type: application/json
- Body:{ "email": "[email protected]", "password": "123456789" }
- Status: 200 OK
- Body: 로그인 성공 시 발급된 JWT 토큰
- 가입한 이메일과 비밀번호로 로그인을 요청합니다.
- 로그인 성공시 jwt 토큰을 발급받습니다.
- 초기 데이터 (2개)
- 상품번호 : 1, 상품명 : 테스트 상품 1, 상품가격 : 10000
- 현재 시점의 상품 스냅샷 (~ing)
- 2012.12.25 ~ 2012.12.30 시점의 상품 스냅샷
- 상품번호 : 2, 상품명 : 테스트 상품 2, 상품가격 : 20000
- 현재 시점의 상품 스냅샷 (~ing)
- 상품번호 : 1, 상품명 : 테스트 상품 1, 상품가격 : 10000
- 엔드포인트: POST /api/v1/products
- Request Body: 게시글 생성 요청 데이터
- productName (문자열): 상품명 (Not Blank)
- price (숫자): 상품 가격 (min = 1000)
- Response: 상품의 정보를 담은 응답 데이터
- Method: POST
- URL: http://localhost:8080/api/v1/products
- Headers:
- Content-Type: application/json
- Authorization: Bearer {JWT_Token} - (MART 권한 필수)
- Body:{ "productName" : "상품입니다.", "price" : "20000" }
- Status: 201 Created
- Body: { "id": 3, "productName": "상품입니다.", "price": 20000 }
- 상품명과 상품 가격으로 상품을 생성할 수 있습니다.
- 마트 권한 계정으로 로그인이 필요합니다.
- 엔드포인트: PATCH /api/v1/products/{productId}
- Request Body: 상품 가격 수정 요청 데이터
- price : 수정하고자 하는 상품 가격
- Response: 수정된 상품의 정보를 담은 응답 데이터
- Method: PATCH
- URL: http://localhost:8080/api/v1/products/{productId}
- Headers:
- Content-Type: application/json
- Authorization: Bearer {JWT_Token} (MART 권한 필수)
- Body:{ "price" : "1000000" }
- Status: 200 OK
- Body: { "id": {productId}, "productName": "테스트 상품 1", "price": 1000000 }
- 상품 가격을 수정합니다.
- 마트 권한 계정으로 로그인이 필요합니다.
- 엔드포인트: DELETE /api/v1/products/{productId}
- Response: 없음
- Method: DELETE
- URL: http://localhost:8080/api/v1/products/{productId}
- Headers:
- Content-Type: application/json
- Authorization: Bearer {JWT_Token} (MART 권한 필수)
- Status: 204 No Content
- 상품 번호로 상품을 삭제합니다.
- 마트 권한 계정으로 로그인이 필요합니다.
- 엔드포인트: GET /api/v1/products/price
- Request Param : productId (상품 ID)
- Request Param : timestamp (찾고자 하는 특정 시점, required=false) (Lodat
- Response: timestamp 시기에 특정 상품의 가격
- Method: GET
- URL: http://localhost:8080/api/v1/products/price?productId=×tamp=
- Headers:
- Authorization: Bearer {JWT_Token}
- Status: 200 OK
- Body: 특정 시점 상품 가격
- timestamp 빈 값이 들어올시 현재 가격을 조회합니다.
- 초기 데이터 (2개)
-
주문번호 : 1, 배송비 : 3000
- 주문품목번호 : 1, 상품번호 : 1 (1만원), 수량 : 5
- 주문품목번호 : 2, 상품번호 : 2 (2만원), 수량 : 2
-
주문번호 : 2, 배송비 : 5000
- 주문품목번호 : 3, 상품번호 : 1 (1만원), 수량 : 2
- 주문품목번호 : 4, 상품번호 : 2 (2만원), 수량 : 10
-
- 엔드포인트: POST /api/v1/orders
- Request Body: 주문 생성 요청 데이터
- orderItemRequestDtoList (json 리스트): 주문품목 요청 데이터 리스트
- productId (숫자) : 주문 품목의 상품 고유 번호 (not null)
- quantity (숫자) : 주문하려는 상품의 수량 (min = 1)
- deliveryFee : 배송비 (not null)
- orderItemRequestDtoList (json 리스트): 주문품목 요청 데이터 리스트
- Method: POST
- URL: http://localhost:8080/api/v1/orders
- Headers:
- Content-Type: application/json
- Authorization: Bearer {JWT_Token}
- Body:{ "orderItemRequestDtoList": [ { "productId": 1, "quantity": 3 }, { "productId": 2, "quantity": 2 } ], "deliveryFee": 5000 }
- Status: 201 Created
- Body: 생성된 주문 번호
- 주문 데이터를 생성합니다.
- 로그인이 필요합니다. (권한은 상관없습니다.)
- 엔드포인트: GET /api/v1/orders/{orderId}/price
- Response: 해당 주문 총금액
- Method: GET
- URL: http://localhost:8080/api/v1/orders/1/price
- Headers:
- Authorization: Bearer {JWT_Token}
- Status: 200 OK
- Body: 주문 총금액
- 특정 주문에 대한 총금액을 조회합니다. (배송비 포함)
- 로그인이 필요합니다. (권한은 상관없습니다.)
-
초기 데이터 (4개)
- 쿠폰 번호 : 1, 적용범위 : 전체주문, 쿠폰종류 : 고정할인쿠폰, 할인금액 : 20000, 쿠폰코드 : "2만원_고정할인_전체주문"
- 쿠폰 번호 : 2, 적용범위 : 특정상품, 쿠폰종류 : 고정할인쿠폰, 할인금액 : 20000, 쿠폰코드 : "2만원_고정할인_특정상품"
- 쿠폰 번호 : 3, 적용범위 : 전체주문, 쿠폰종류 : 비율할인쿠폰, 할인율 : 10%, 쿠폰코드 : "10퍼센트_비율할인_전체주문"
- 쿠폰 번호 : 4, 적용범위 : 특정상품, 쿠폰종류 : 고정할인쿠폰, 할인율 : 10%, 쿠폰코드 : "10퍼센트_비율할인_특정상품"
-
본래 쿠폰 코드는 UUID 랜덤값이지만 원활한 테스트를 위해서 직접 생성했습니다.
- 엔드포인트: POST /api/v1/orders/{orderId}/calculate-paymentPrice
- request param : couponCode (할인 쿠폰 코드, required=false)
- request param : orderItemId (할인 쿠폰 코드 적용하고자 하는 특정 주문 품목, required=false)
- Response: 주문에 대한 필요 결제 금액
- Method: POST
- URL: http://localhost:8080/api/v1/orders/1/calculate-paymentPrice?couponCode=2만원_고정할인_특정상품&orderItemId=1
- Headers:
- Authorization: Bearer {JWT_Token}
- Status: 200 OK
- Body: 주문에 대한 필요 결제 금액
- 특정 주문에 대한 결제 금액을 조회합니다.
- 쿠폰 코드를 사용해 쿠폰 적용이 가능합니다.
- 쿠폰은 주문 당 하나만 적용이 가능하다고 가정합니다.
- 고정할인쿠폰 / 비율할인쿠폰은 쿠폰 코드에 따라 다릅니다.
- orderItemId 값의 유/무에 따라 전체주문, 특정상품 적용범위를 결정합니다.
- 로그인이 필요합니다. (권한은 상관없습니다.)
- 테이블 생성
- 현재는 jpa 의 ddl-auto : create 를 통해 테이블을 자동으로 생성하고 있습니다. 하지만 이 방법은 생성되어 있지 않은 테이블에 대해서 alter 문이 생성되며 잠시 발생하는 오류를 확인할 수 있습니다. 물론 조금만 있으면 애플리케이션이 정상적으로 실행되지만 개선할 필요가 있을 것 같습니다.
- 개선 방법으로는 init.sql 에 직접 쿼리문을 작성해서 테이블을 생성해주는 것을 고려했습니다. 조금 더 공부해본 후 적용해보도록 하겠습니다.