Skip to content

Commit f6a0db3

Browse files
authored
[CHORE] develop 변경사항 main 반영 (#66)
2 parents 6acd71d + a047ac9 commit f6a0db3

259 files changed

Lines changed: 13236 additions & 107 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI (develop)
22

33
on:
44
pull_request:
5-
branches: [ "develop" ]
5+
branches: ["main", "develop" ]
66

77
permissions:
88
contents: read

.github/workflows/cicd-dev.yml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: CI/CD (develop)
2+
3+
on:
4+
push:
5+
branches: [ "develop" ]
6+
7+
permissions:
8+
contents: read
9+
10+
concurrency:
11+
group: valuedi-dev-deploy
12+
cancel-in-progress: true
13+
14+
jobs:
15+
build-and-push:
16+
runs-on: ubuntu-latest
17+
18+
outputs:
19+
image_repo: ${{ steps.meta.outputs.image_repo }}
20+
image_tag: ${{ steps.meta.outputs.image_tag }}
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4.2.2
25+
26+
- name: Set up QEMU
27+
uses: docker/setup-qemu-action@v3
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3.10.0
31+
32+
- name: Log in to Docker Hub
33+
uses: docker/login-action@v3.4.0
34+
with:
35+
username: ${{ secrets.DOCKER_USERNAME }}
36+
password: ${{ secrets.DOCKER_PASSWORD }}
37+
38+
- name: Set image meta
39+
id: meta
40+
run: |
41+
echo "image_repo=${{ secrets.DOCKER_USERNAME }}/valuedi-backend" >> $GITHUB_OUTPUT
42+
echo "image_tag=${{ github.sha }}" >> $GITHUB_OUTPUT
43+
44+
- name: Build & Push (ARM64)
45+
uses: docker/build-push-action@v6.16.0
46+
with:
47+
context: .
48+
file: ./Dockerfile
49+
push: true
50+
platforms: linux/arm64 # 라즈베리 파이용
51+
tags: |
52+
${{ steps.meta.outputs.image_repo }}:dev-latest
53+
${{ steps.meta.outputs.image_repo }}:${{ steps.meta.outputs.image_tag }}
54+
cache-from: type=gha
55+
cache-to: type=gha,mode=max
56+
57+
deploy:
58+
runs-on: ubuntu-latest
59+
needs: build-and-push
60+
61+
steps:
62+
- name: Deploy via SSH (Blue/Green)
63+
uses: appleboy/ssh-action@v1.2.2
64+
with:
65+
host: ${{ secrets.DEV_SERVER_HOST }} # 개발 서버 IP
66+
port: ${{ secrets.DEV_SERVER_PORT }} # 개발 서버 SSH 포트
67+
username: ${{ secrets.DEV_SERVER_USERNAME }} # 개발 서버 유저 (예: pi)
68+
key: ${{ secrets.DEV_SERVER_KEY }} # 개발 서버 SSH Key
69+
script_stop: true
70+
script: |
71+
set -euo pipefail
72+
73+
APP_DIR="/home/${{ secrets.DEV_SERVER_USERNAME }}/valuedi/app" # 라즈베리 파이 경로
74+
cd "$APP_DIR"
75+
76+
# 1) DEV_ENV를 .env로 반영
77+
cat > .env << 'EOF'
78+
${{ secrets.DEV_ENV }}
79+
EOF
80+
81+
# 2) IMAGE_REPO / IMAGE_TAG 주입
82+
IMAGE_REPO="${{ secrets.DOCKER_USERNAME }}/valuedi-backend"
83+
IMAGE_TAG="${{ github.sha }}"
84+
85+
if grep -q '^IMAGE_REPO=' .env; then
86+
sed -i "s|^IMAGE_REPO=.*|IMAGE_REPO=${IMAGE_REPO}|" .env
87+
else
88+
echo "IMAGE_REPO=${IMAGE_REPO}" >> .env
89+
fi
90+
91+
if grep -q '^IMAGE_TAG=' .env; then
92+
sed -i "s|^IMAGE_TAG=.*|IMAGE_TAG=${IMAGE_TAG}|" .env
93+
else
94+
echo "IMAGE_TAG=${IMAGE_TAG}" >> .env
95+
fi
96+
97+
# 3) 배포 스크립트 실행
98+
# (스크립트 파일들이 실행 권한이 있는지 확인)
99+
chmod +x deploy.sh scripts/healthcheck.sh scripts/switch_upstream.sh
100+
./deploy.sh
101+
102+
# 4) 정리
103+
docker image prune -f

build.gradle

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ repositories {
2424
mavenCentral()
2525
}
2626

27+
ext {
28+
set('springCloudVersion', "2025.1.0") // 스프링 부트 버전에 맞춰 조절 필요
29+
}
30+
2731
dependencies {
2832
// Spring Boot Core
2933
implementation 'org.springframework.boot:spring-boot-starter-validation'
3034
implementation 'org.springframework.boot:spring-boot-starter-web'
35+
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
36+
implementation 'org.springframework.boot:spring-boot-starter-webflux'
3137
implementation 'org.springframework.boot:spring-boot-starter-actuator'
38+
implementation 'com.google.genai:google-genai:1.0.0'
3239

3340
// Lombok
3441
compileOnly 'org.projectlombok:lombok'
@@ -47,14 +54,60 @@ dependencies {
4754
testRuntimeOnly 'com.h2database:h2'
4855

4956
// Swagger
50-
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13'
51-
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.13'
57+
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1'
58+
59+
// CODEF
60+
implementation 'io.codef.api:easycodef-java:1.0.6'
61+
62+
// Spring Cloud OpenFeign
63+
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
5264

5365
// Security
5466
implementation 'org.springframework.boot:spring-boot-starter-security'
5567
testImplementation 'org.springframework.security:spring-security-test'
68+
69+
// Jwt
70+
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
71+
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
72+
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
73+
implementation 'org.springframework.boot:spring-boot-configuration-processor'
74+
75+
// QueryDSL : OpenFeign
76+
implementation "io.github.openfeign.querydsl:querydsl-jpa:7.0"
77+
implementation "io.github.openfeign.querydsl:querydsl-core:7.0"
78+
annotationProcessor "io.github.openfeign.querydsl:querydsl-apt:7.0:jpa"
79+
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
80+
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
81+
82+
// mail
83+
implementation'org.springframework.boot:spring-boot-starter-mail'
84+
85+
// async
86+
implementation 'org.springframework.retry:spring-retry'
87+
implementation 'org.springframework:spring-aspects'
88+
89+
}
90+
91+
dependencyManagement {
92+
imports {
93+
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
94+
}
5695
}
5796

5897
tasks.named('test') {
5998
useJUnitPlatform()
99+
}
100+
101+
// QueryDSL 관련 설정
102+
// generated/querydsl 폴더 생성 & 삽입
103+
def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
104+
105+
// 컴파일 시 생성 경로 지정
106+
tasks.withType(JavaCompile).configureEach {
107+
options.generatedSourceOutputDirectory.set(querydslDir)
108+
}
109+
110+
// clean 태스크에 생성 폴더 삭제 로직 추가
111+
clean.doLast {
112+
file(querydslDir).deleteDir()
60113
}

gradlew

100755100644
File mode changed.

src/main/java/org/umc/valuedi/ValuediApplication.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
6+
import org.springframework.cloud.openfeign.EnableFeignClients;
57
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
8+
import org.springframework.scheduling.annotation.EnableScheduling;
69

710
@SpringBootApplication
811
@EnableJpaAuditing
12+
@EnableFeignClients
13+
@EnableScheduling
14+
@ConfigurationPropertiesScan
915
public class ValuediApplication {
1016
public static void main(String[] args) {
1117
SpringApplication.run(ValuediApplication.class, args);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.umc.valuedi.domain.asset.controller;
2+
3+
import io.swagger.v3.oas.annotations.tags.Tag;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.PathVariable;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
import org.umc.valuedi.domain.asset.dto.res.AssetResDTO;
10+
import org.umc.valuedi.domain.asset.dto.res.BankResDTO;
11+
import org.umc.valuedi.domain.asset.dto.res.CardResDTO;
12+
import org.umc.valuedi.domain.asset.service.AssetQueryService;
13+
import org.umc.valuedi.domain.connection.service.ConnectionQueryService;
14+
import org.umc.valuedi.global.apiPayload.ApiResponse;
15+
import org.umc.valuedi.global.apiPayload.code.GeneralSuccessCode;
16+
import org.umc.valuedi.global.security.annotation.CurrentMember;
17+
18+
import java.util.List;
19+
20+
@RestController
21+
@RequiredArgsConstructor
22+
@RequestMapping("/api/assets")
23+
@Tag(name = "Asset", description = "자산 관련 조회 API")
24+
public class AssetController implements AssetControllerDocs {
25+
26+
private final ConnectionQueryService connectionQueryService;
27+
private final AssetQueryService assetQueryService;
28+
29+
30+
@GetMapping("/cards")
31+
public ApiResponse<CardResDTO.CardListDTO> getCards(
32+
@CurrentMember Long memberId
33+
) {
34+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, assetQueryService.getAllCards(memberId));
35+
}
36+
37+
@GetMapping("/cardIssuers")
38+
public ApiResponse<List<CardResDTO.CardIssuerConnection>> getCardIssuers(
39+
@CurrentMember Long memberId
40+
) {
41+
List<CardResDTO.CardIssuerConnection> cardIssuers = connectionQueryService.getConnectedCardIssuers(memberId);
42+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, cardIssuers);
43+
}
44+
45+
@GetMapping("/cardIssuers/{issuerCode}/cards")
46+
public ApiResponse<CardResDTO.CardListDTO> getCardsByIssuer(
47+
@PathVariable String issuerCode,
48+
@CurrentMember Long memberId
49+
) {
50+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, assetQueryService.getCardsByIssuer(memberId, issuerCode));
51+
}
52+
53+
@GetMapping("/banks")
54+
public ApiResponse<List<BankResDTO.BankConnection>> getBanks( // TODO: List 객체 래핑으로 변경
55+
@CurrentMember Long memberId
56+
) {
57+
List<BankResDTO.BankConnection> banks = connectionQueryService.getConnectedBanks(memberId);
58+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, banks);
59+
}
60+
61+
@GetMapping("/accounts")
62+
public ApiResponse<BankResDTO.BankAccountListDTO> getAllBankAccounts(
63+
@CurrentMember Long memberId
64+
) {
65+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, assetQueryService.getAllBankAccounts(memberId));
66+
}
67+
68+
@GetMapping("/banks/{bankCode}/accounts")
69+
public ApiResponse<BankResDTO.BankAccountListDTO> getAccountsByBank(
70+
@PathVariable String bankCode,
71+
@CurrentMember Long memberId
72+
) {
73+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, assetQueryService.getBankAccountsByOrganization(memberId, bankCode));
74+
}
75+
76+
@GetMapping("/summary")
77+
public ApiResponse<AssetResDTO.AssetSummaryCountDTO> getAssetCount(
78+
@CurrentMember Long memberId
79+
) {
80+
return ApiResponse.onSuccess(GeneralSuccessCode.OK, assetQueryService.getAssetSummaryCount(memberId));
81+
}
82+
}

0 commit comments

Comments
 (0)