Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a329db7
[Docs] 프로젝트 생성
subin930 Dec 29, 2025
4d8291c
[Docs] 도메인 분리
subin930 Dec 30, 2025
ff4c0f8
[Docs] API Gateway, Eureka Server 구축
subin930 Dec 30, 2025
659bf20
[Remove] infra:config 모듈 삭제
subin930 Dec 31, 2025
924ce0d
Merge pull request #3 from Central-MakeUs/docs/#1
subin930 Dec 31, 2025
6b10bec
[Feat] CI/CD 파이프라인 구축
subin930 Jan 2, 2026
992b273
[Feat] 프로필 분리 구성
subin930 Jan 2, 2026
0d9d284
Merge pull request #4 from Central-MakeUs/docs/#2
subin930 Jan 2, 2026
39de703
[Feat] 프로필 분리 구성 서비스명 수정
subin930 Jan 2, 2026
530bcb0
Merge pull request #5 from Central-MakeUs/docs/#2
subin930 Jan 2, 2026
aea212c
Merge pull request #6 from Central-MakeUs/feat/#2
subin930 Jan 2, 2026
3259ed9
[Fix] cicd 파일 내 모듈 경로 수정
subin930 Jan 2, 2026
c6d0b5c
Merge pull request #9 from Central-MakeUs/fix/#8
subin930 Jan 2, 2026
af47678
[Fix] 모듈 별 도커파일 추가
subin930 Jan 2, 2026
181f6cf
Merge pull request #12 from Central-MakeUs/bug/#11
subin930 Jan 2, 2026
5cb0bbb
Merge branch 'main' of https://github.com/Central-MakeUs/Chord_Server…
subin930 Jan 3, 2026
eff4b70
[Feat] 응답/에러 형식 통일
subin930 Jan 4, 2026
2080e8f
[Feat] 스웨거 적용 및 헤더 추가
subin930 Jan 5, 2026
fbeace9
[Fix] 스웨거 및 응답형식 오류 수정
subin930 Jan 5, 2026
667fa10
[Fix] 스웨거 및 응답형식 오류 수정
subin930 Jan 5, 2026
252c7ee
Merge remote-tracking branch 'origin/feature/#14' into feature/#14
subin930 Jan 5, 2026
59ad876
Merge pull request #15 from Central-MakeUs/feature/#14
subin930 Jan 5, 2026
bf4fb4f
[Feat] 재료 카테고리 등록 구현
subin930 Jan 5, 2026
35033d2
[Feat] 메뉴 카테고리 등록 구현
subin930 Jan 5, 2026
2cad8e8
[Feat] 재료/메뉴 카테고리 목록 조회 구현
subin930 Jan 6, 2026
cfdbd38
[Fix] catalog 모듈 프로필 분리
subin930 Jan 7, 2026
78e5c10
[Fix] gateway 모듈 프로필 분리
subin930 Jan 7, 2026
3bd748a
[Fix] env 파일 적용
subin930 Jan 7, 2026
4d3a033
Merge pull request #17 from Central-MakeUs/feature/#16
subin930 Jan 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions coachcoach/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PRIVATE_EC2_1_HOST=
PRIVATE_EC2_1_SSH_KEY=
PRIVATE_EC2_2_HOST=
PRIVATE_EC2_2_SSH_KEY=
PUBLIC_EC2_1_HOST=
PUBLIC_EC2_1_SSH_KEY=
QUAY_TOKEN=
EUREKA_URL=
MANAGEMENT_ENDPOINTS=health,info,prometheus,metrics
SPRING_PROFILES_ACTIVE=prod
DATASOURCE_URL=
DATASOURCE_USERNAME=
DATASOURCE_PASSWORD=
3 changes: 1 addition & 2 deletions coachcoach/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@ gradle-app.setting

### yml/yaml ###
application-dev.yml
.env
.env.*
common.env
!application.yml
!application.properties

Expand Down
8 changes: 7 additions & 1 deletion coachcoach/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
id 'org.springframework.boot' version '3.3.2' apply false
}

group = 'chord'
group = 'com.coachcoach'
version = '0.0.1-SNAPSHOT'

allprojects {
Expand All @@ -22,6 +22,12 @@ subprojects {
targetCompatibility = JavaVersion.VERSION_21
}

dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:3.3.2"
}
}

dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
16 changes: 16 additions & 0 deletions coachcoach/common/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id 'java-library'
id 'io.spring.dependency-management'
}

dependencies {
compileOnly 'org.springframework.boot:spring-boot-starter-web'
api 'org.springframework.boot:spring-boot-starter-validation'

api 'com.fasterxml.jackson.core:jackson-databind'
api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
}

jar {
enabled = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.coachcoach.common.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;

import java.time.LocalDateTime;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> {

@Builder.Default
private boolean success = true; // 성공 여부

private String message; // 응답 메시지(선택)

private T data; //실제 데이터

@Builder.Default
private LocalDateTime timestamp = LocalDateTime.now(); // 응답 시간

@JsonIgnore
@Builder.Default
private HttpStatus status = HttpStatus.OK;

// Data
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.success(true)
.data(data)
.status(HttpStatus.OK)
.build();
}

// Data + Message
public static <T> ApiResponse<T> success(T data, String message) {
return ApiResponse.<T>builder()
.success(true)
.message(message)
.data(data)
.status(HttpStatus.OK)
.build();
}

// Message - Data X
public static ApiResponse<Void> success(String message) {
return ApiResponse.<Void>builder()
.success(true)
.message(message)
.status(HttpStatus.OK)
.build();
}

public static <T> ApiResponse<T> success(T data, HttpStatus status) {
return ApiResponse.<T>builder()
.success(true)
.data(data)
.status(status)
.build();
}

public HttpStatus httpStatus() {
return status;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.coachcoach.common.dto;

import com.coachcoach.common.exception.ErrorCode;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Map;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ErrorResponse {

@Builder.Default
private boolean success = false; // 실패

private String code; // 에러 코드

private String message; // 에러 메시지

private Map<String, String> errors; // Validation 에러

@Builder.Default
private LocalDateTime timestamp = LocalDateTime.now(); // 응답 시간

// ErrorCode Enum 활용 에러
public static ErrorResponse of(ErrorCode errorCode) {
return ErrorResponse.builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.build();
}

// code + message 직접 작성
public static ErrorResponse of(String code, String message) {
return ErrorResponse.builder()
.code(code)
.message(message)
.build();
}

// Validation 에러
public static ErrorResponse of(String code, String message, Map<String, String> errors) {
return ErrorResponse.builder()
.code(code)
.message(message)
.errors(errors)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.coachcoach.common.exception;

import lombok.Getter;

@Getter
public class BusinessException extends RuntimeException {
private final ErrorCode errorCode;

public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}

public BusinessException(ErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.coachcoach.common.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum CommonErrorCode implements ErrorCode {
// 공통 에러
INVALID_INPUT_VALUE("COMMON_001", "입력값이 올바르지 않습니다", HttpStatus.BAD_REQUEST),
METHOD_NOT_ALLOWED("COMMON_002", "지원하지 않는 HTTP 메서드입니다", HttpStatus.METHOD_NOT_ALLOWED),
INTERNAL_SERVER_ERROR("COMMON_003", "서버 내부 오류가 발생했습니다", HttpStatus.INTERNAL_SERVER_ERROR),
INVALID_TYPE_VALUE("COMMON_004", "잘못된 타입입니다", HttpStatus.BAD_REQUEST),
MISSING_REQUEST_PARAMETER("COMMON_005", "필수 파라미터가 누락되었습니다", HttpStatus.BAD_REQUEST),
SERVICE_UNAVAILABLE("COMMON_006", "서비스에 연결할 수 없습니다", HttpStatus.SERVICE_UNAVAILABLE),
NOT_FOUND("COMMON_007", "요청하신 자원을 찾을 수 없습니다.", HttpStatus.NOT_FOUND),

// 인증/인가
UNAUTHORIZED("AUTH_001", "인증이 필요합니다", HttpStatus.UNAUTHORIZED),
FORBIDDEN("AUTH_002", "접근 권한이 없습니다", HttpStatus.FORBIDDEN),
INVALID_TOKEN("AUTH_003", "유효하지 않은 토큰입니다", HttpStatus.UNAUTHORIZED),
;

private final String code;
private final String message;
private final HttpStatus httpStatus;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.coachcoach.common.exception;

import org.springframework.http.HttpStatus;

public interface ErrorCode {
String getCode();
String getMessage();
HttpStatus getHttpStatus();
}
6 changes: 4 additions & 2 deletions coachcoach/docker/private1-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ services:
network_mode: "host"
ports:
- "9000:9000"
env_file:
- common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://10.0.0.107:8761/eureka/
restart: unless-stopped

user-store:
Expand All @@ -18,9 +19,10 @@ services:
network_mode: "host"
ports:
- "9001:9001"
env_file:
- common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://10.0.0.107:8761/eureka/
restart: unless-stopped

networks:
Expand Down
6 changes: 4 additions & 2 deletions coachcoach/docker/private2-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ services:
network_mode: "host"
ports:
- "9002:9002"
env_file:
- common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://10.0.0.107:8761/eureka/
restart: unless-stopped

insight:
Expand All @@ -18,9 +19,10 @@ services:
network_mode: "host"
ports:
- "9003:9003"
env_file:
- common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://10.0.0.107:8761/eureka/
restart: unless-stopped

networks:
Expand Down
3 changes: 2 additions & 1 deletion coachcoach/docker/public1-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ services:
container_name: gateway
ports:
- "8080:8000"
env_file:
- common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka:8761/eureka/
- JAVA_OPTS=-Xmx128m -Xms64m
networks:
- coachcoach-network
Expand Down
4 changes: 4 additions & 0 deletions coachcoach/infra/gateway/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.4.0'

implementation project(':common')
developmentOnly 'org.springframework.boot:spring-boot-devtools'
}

dependencyManagement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,23 @@ public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("auth-service",
p -> p.path("/api/auth/**")
.filters(f -> f.rewritePath("/api/auth/(?<segment>.*)", "/${segment}"))
.uri("lb://auth-service"))
.route("user-store-service",
p -> p.path("/api/user-store/**")
.filters(f -> f.rewritePath("/api/user-store/(?<segment>.*)", "/${segment}"))
.uri("lb://user-store-service"))
.route("catalog-service",
p -> p.path("/api/catalog/**")
.filters(
f -> f
.rewritePath("/api/catalog/(?<segment>.*)", "/${segment}")
.addRequestHeader("userId", "1")
)
.uri("lb://catalog-service"))
.route("insight-service",
p -> p.path("/api/insight/**")
.filters(f -> f.rewritePath("/api/insight/(?<segment>.*)", "/${segment}"))
.uri("lb://insight-service"))
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.coachcoach.gateway.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.openapi("3.0.0")
.info(new Info()
.title("코치코치 API")
.version("v1"));
}
}
Loading