Skip to content

Commit 8c0b0c7

Browse files
committed
Merge branch 'develop'
# Conflicts: # .github/workflows/deploy.yml # Dockerfile
2 parents 3e110dc + f97655b commit 8c0b0c7

File tree

378 files changed

+20066
-428
lines changed

Some content is hidden

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

378 files changed

+20066
-428
lines changed

โ€Ž.gitignoreโ€Ž

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ out/
3737
### VS Code ###
3838
.vscode/
3939

40-
### H2 DB file ###
40+
# Ignore H2 database files
4141
*.mv.db
42-
*.trace.db
42+
*.trace.db
43+
44+
#secret yml#
45+
application-secret.yml
46+
/src/main/resources/firebase/firebase_service_key.json

โ€ŽREADME.mdโ€Ž

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,80 @@
1-
# WEB1_2_Child-Learn_BE
1+
# ์•„์ด์ฃผ์ฃผ ![์•„์ด์ฃผ์ฃผ 3](https://github.com/user-attachments/assets/89cd492b-92fe-46ef-b7f2-319e8df4c400)
2+
3+
![ํ”„๋กœ์ ํŠธ์ด๋ฏธ์ง€](https://github.com/user-attachments/assets/6e0bdf74-a374-4c70-952d-fc22e0ba3413)
4+
5+
## ๐Ÿ€ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ
6+
์•„์ด์ฃผ์ฃผ๋Š” ์ดˆ๋“ฑํ•™์ƒ๋“ค์ด ๋ˆ๊ณผ ํˆฌ์ž์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์„ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋œ ๋ชจ์˜ํˆฌ์ž ํ•™์Šต ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.
7+
8+
[๐Ÿ”— ๊ธฐํš์„œ](https://www.notion.so/13f336d06fda80d4a0dfc9e9ac30e96b?pvs=4)
9+
[๐Ÿ”— ๋””์ž์ธ](https://www.figma.com/design/HfCXjOdS1CcDWLJbhci0dI/%EC%95%84%EC%9D%B4%EC%A3%BC%EC%A3%BC-%EC%99%80%EC%9D%B4%EC%96%B4%ED%94%84%EB%A0%88%EC%9E%84?node-id=0-1&t=WB1ZEVppjZTp8DY5-1)
10+
[๐Ÿ”— ํ”„๋ก ํŠธ ๊นƒํ—ˆ๋ธŒ](https://github.com/prgrms-web-devcourse-final-project/WEB1_2_Child-Learn_FE)
11+
[๐Ÿ”— ๋ฐฑ์—”๋“œ ๊นƒํ—ˆ๋ธŒ](https://github.com/prgrms-web-devcourse-final-project/WEB1_2_Child-Learn_BE)
12+
[๐Ÿ”— ์•„์ด์ฃผ์ฃผ ๋ฐ”๋กœ๊ฐ€๊ธฐ](http://ijuju.site)
13+
14+
### ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ : 2024/11/18 ~ 2024/12/09
15+
16+
<br>
17+
18+
19+
## ๐Ÿ€ ์ฃผ์š” ๊ธฐ๋Šฅ
20+
> **์ฃผ์‹ ๊ทธ๋ž˜ํ”„**
21+
- **๊ทธ๋ž˜ํ”„ ๋ฐ ๋ฐ์ดํ„ฐ ์ œ๊ณต:** ์ข…๋ชฉ๋ณ„ ํˆฌ์ž ๊ทธ๋ž˜ํ”„์™€ ๋น„์œ ์  ์„ค๋ช…์ด ๋‹ด๊ธด ๋‰ด์Šค๋ ˆํ„ฐ ์ œ๊ณต
22+
- **AI ๋งž์ถคํ˜• ์ •๋ณด:** API๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ๋ฐ ๋งž์ถคํ˜• ๋‰ด์Šค ์•„ํ‹ฐํด ์ œ๊ณต
23+
- **๋žœ๋ค์„ฑ๊ณผ ํ˜„์‹ค์„ฑ:** ๋žœ๋ค ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ์‹ค์ œ ๊ฒฝ์ œ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ผํ•ฉํ•ด ์žฌ๋ฏธ์žˆ๊ณ  ํ˜„์‹ค๊ฐ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„ ๋ณ€ํ™” ์ œ๊ณต
24+
25+
> **๋ฏธ๋‹ˆ๊ฒŒ์ž„**
26+
27+
์•„์ด๋“ค์˜ ํฅ๋ฏธ๋ฅผ ์œ ๋ฐœํ•˜๊ณ , ํ•™์Šต ํšจ๊ณผ๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๋ฏธ๋‹ˆ๊ฒŒ์ž„
28+
- **์นด๋“œ ๋’ค์ง‘๊ธฐ**: ํˆฌ์ž ๊ด€๋ จ์šฉ์–ด๋ฅผ ๊ฒŒ์ž„์œผ๋กœ ๊ฐœ๋… ์ดํ•ด.
29+
- **๊ธˆ์œต ํ€ด์ฆˆ:** ๋ˆ, ์ €์ถ•, ํˆฌ์ž ๊ด€๋ จ ํ€ด์ฆˆ๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ ๊ฐœ๋… ์ดํ•ด.
30+
- **๋กœ๋˜:** ๊ฐ„๋‹จํ•œ ํ™•๋ฅ  ๊ฒŒ์ž„์œผ๋กœ ํˆฌ์ž์™€ ์œ„ํ—˜์˜ ๊ฐœ๋… ์ดํ•ด.
31+
32+
> **์ƒ์ **
33+
- ๊ฒŒ์ž„ ๋ฐ ์ฃผ์‹ํˆฌ์ž๋ฅผ ํ†ตํ•˜์—ฌ ํš๋“ํ•œ ํฌ์ธํŠธ๋กœ ์ƒ์ ๊ธฐ๋Šฅ ์ œ๊ณต.
34+
- ์ƒ์ ์—์„œ ์ž์‹ ๋งŒ์˜ ์•„๋ฐ”ํƒ€๋ฅผ ๊พธ๋ฐ€ ์ˆ˜ ์žˆ๋Š” ์•„์ดํ…œ ์ œ๊ณต.
35+
- ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์•„์ดํ…œ์œผ๋กœ ํฅ๋ฏธ ์ œ๊ณต.
36+
37+
<br>
38+
39+
## ๐Ÿ€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ
40+
### ํ†ตํ•ฉ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜
41+
![ํ†ตํ•ฉ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜](https://github.com/user-attachments/assets/f6ddd958-6a68-4305-84c3-3e6f8098633f)
42+
43+
<br>
44+
45+
## ๐Ÿ€ ๊ฐœ๋ฐœ ๋ฌธ์„œ
46+
<details>
47+
<summary>ERD</summary>
48+
</details>
49+
<details>
50+
<summary>์•„ํ‚คํ…์ฒ˜</summary>
51+
52+
![๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์•„ํ‚คํ…์ฒ˜](https://github.com/user-attachments/assets/f96d2c88-223c-47b4-a673-ac613be39063)
53+
54+
</details>
55+
<details>
56+
<summary>์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ์„œ</summary>
57+
58+
[๐Ÿ”— ์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ์„œ](https://foggy-move-190.notion.site/67c1e522ca8047d98094580d9bdc8f87?pvs=74)
59+
</details>
60+
<details>
61+
<summary>API ๋ช…์„ธ์„œ</summary>
62+
63+
[๐Ÿ”— API ๋ช…์„ธ์„œ](https://foggy-move-190.notion.site/API-b44b55ec93c9478c9a25c9f75150b773?pvs=73)
64+
</details>
65+
66+
## ๐Ÿ€ ํŒ€ ์†Œ๊ฐœ
67+
68+
### FRONTEND
69+
| ๐Ÿ‘‘ ์ดํฌ์ฃผ | ๐Ÿ“‹ ๋ฐ•์šฐํ˜„ | ๋ฅ˜๋ฏผ์ฃผ |
70+
|:----------------------------------------------------------:|:----------------------------------------------------------:|:-------------------------------------:|
71+
| FE TeamLeader | PM | Git_Admin |
72+
| [tree0000](https://github.com/tree0000) | [hjlee2778](https://github.com/hjlee2778) | [minij02](https://github.com/minij02) |
73+
| ![](https://avatars.githubusercontent.com/u/141895600?v=4) | ![](https://avatars.githubusercontent.com/u/144092849?v=4) | ![](https://avatars.githubusercontent.com/u/135093109?v=4)|
74+
75+
### BACKEND
76+
| ๐Ÿ‘‘ ์ž„์ง€์€ | ์‹ ์€ํ™” | ์ตœ์žฌํ˜• | ์ด์ˆ˜๋นˆ | ๋ฐ•์ฐฌ์„œ |
77+
|:---------------------------------:|:-----------------------------------------:|:--------------------------------:|:---------------------------------------:|:---------------------------------------:|
78+
| BE TeamLeader & AWS_Admin | Git_Admin | Developer | Developer | Developer |
79+
| [1mjay](https://github.com/1mjay) | [deveunhwa](https://github.com/deveunhwa) | [Preta3418](https://github.com/Preta3418) | [subbb-in](https://github.com/subbb-in) | [chanspar](https://github.com/chanspar) |
80+
| ![](https://avatars.githubusercontent.com/u/84836677?v=4) | ![](https://avatars.githubusercontent.com/u/180101230?v=4) | ![](https://avatars.githubusercontent.com/u/161911738?v=4) | ![](https://avatars.githubusercontent.com/u/48655473?v=4) | ![](https://avatars.githubusercontent.com/u/87303538?v=4) |

โ€Žbuild.gradleโ€Ž

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,73 @@ repositories {
2424
}
2525

2626
dependencies {
27+
// jpa
2728
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
29+
30+
// SMTP
2831
implementation 'org.springframework.boot:spring-boot-starter-mail'
32+
// security
2933
implementation 'org.springframework.boot:spring-boot-starter-security'
34+
testImplementation 'org.springframework.security:spring-security-test'
35+
36+
// JWT
37+
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
38+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', 'io.jsonwebtoken:jjwt-jackson:0.12.3'
39+
40+
41+
// validation
3042
implementation 'org.springframework.boot:spring-boot-starter-validation'
43+
44+
// spring web
3145
implementation 'org.springframework.boot:spring-boot-starter-web'
46+
47+
// lombok
3248
compileOnly 'org.projectlombok:lombok'
49+
annotationProcessor 'org.projectlombok:lombok'
50+
51+
// devtools
3352
developmentOnly 'org.springframework.boot:spring-boot-devtools'
53+
54+
// DB
3455
runtimeOnly 'com.h2database:h2'
3556
runtimeOnly 'com.mysql:mysql-connector-j'
36-
annotationProcessor 'org.projectlombok:lombok'
57+
implementation 'mysql:mysql-connector-java:8.0.33'
58+
59+
// test
3760
testImplementation 'org.springframework.boot:spring-boot-starter-test'
38-
testImplementation 'org.springframework.security:spring-security-test'
3961
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
4062

4163
// Querydsl
4264
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
4365
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
4466
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
4567
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
68+
69+
// WebSocket + STOMP
70+
implementation 'org.springframework.boot:spring-boot-starter-websocket'
71+
72+
// Redis
73+
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
74+
75+
// MongoDB
76+
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
77+
78+
//OAuth2.0
79+
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
80+
81+
// Spring Cache - caffeine
82+
implementation 'org.springframework.boot:spring-boot-starter-cache'
83+
implementation 'com.github.ben-manes.caffeine:caffeine'
4684
}
4785

4886
tasks.named('test') {
4987
useJUnitPlatform()
5088
}
89+
90+
tasks.withType(JavaExec) {
91+
jvmArgs += ['--add-opens', 'java.base/java.io=ALL-UNNAMED']
92+
}
93+
94+
test {
95+
jvmArgs += ['--add-opens', 'java.base/java.io=ALL-UNNAMED']
96+
}

โ€Žsrc/main/java/com/prgrms/ijuju/IjujuApplication.javaโ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
6+
import org.springframework.scheduling.annotation.EnableScheduling;
57

8+
@EnableScheduling
9+
@EnableJpaAuditing
610
@SpringBootApplication
711
public class IjujuApplication {
812

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.prgrms.ijuju.domain.article.component;
2+
3+
import com.prgrms.ijuju.domain.article.data.DailyTrend;
4+
import com.prgrms.ijuju.domain.article.data.Trend;
5+
import com.prgrms.ijuju.domain.stock.adv.advstock.entity.AdvStock;
6+
import org.springframework.stereotype.Component;
7+
8+
import java.time.Instant;
9+
import java.time.LocalDate;
10+
import java.time.ZoneId;
11+
import java.util.ArrayList;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
/**
17+
* Adv ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” timeStamp ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ, ํ•œ์‹œ๊ฐ„ ๋ด‰์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค
18+
* ๋ฐ์ดํ„ฐ ๋ถ„์„์„ ์œ„ํ•ด์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ "ํ•˜๋ฃจ" ๋‹จ์œ„๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค
19+
*/
20+
@Component
21+
public class AdvTrendAnalyzer {
22+
23+
24+
public List<Trend> analyzeTrends(AdvStock advStock) {
25+
Map<LocalDate, List<Double>> groupedData = groupByDate(advStock.getTimestamps(), advStock.getClosePrices());
26+
27+
List<DailyTrend> dailyTrends = calculateDailyTrends(groupedData);
28+
29+
return calculateCompositeTrends(dailyTrends, advStock.getSymbol());
30+
}
31+
32+
// ํ•œ ์‹œ๊ฐ„ ๋‹จ์œ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ผ ๋‹จ์œ„๋กœ ๋ฌถ์Œ
33+
// AdvStock ์€ timeStamps ๋กœ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๊ธฐ์—, LocalData ๋กœ ๋ณ€ํ™˜ํ•  ๊ณผ์ •์ด ํ•„์š”ํ•˜๊ธฐ์— ์ƒ์„ฑ๋œ ๋ฉ”์†Œ๋“œ ์ž…๋‹ˆ๋‹ค
34+
private Map<LocalDate, List<Double>> groupByDate(List<Long> timestamps, List<Double> closePrices) {
35+
Map<LocalDate, List<Double>> groupedData = new HashMap<>();
36+
37+
for (int i = 0; i < timestamps.size(); i++) {
38+
LocalDate date = Instant.ofEpochMilli(timestamps.get(i)).atZone(ZoneId.systemDefault()).toLocalDate();
39+
groupedData.computeIfAbsent(date, k -> new ArrayList<>()).add(closePrices.get(i));
40+
}
41+
42+
return groupedData;
43+
}
44+
45+
46+
private List<DailyTrend> calculateDailyTrends(Map<LocalDate, List<Double>> groupedData) {
47+
List<DailyTrend> dailyTrends = new ArrayList<>();
48+
49+
for (Map.Entry<LocalDate, List<Double>> entry : groupedData.entrySet()) {
50+
List<Double> dailyPrices = entry.getValue();
51+
double startPrice = dailyPrices.get(0);
52+
double endPrice = dailyPrices.get(dailyPrices.size() - 1);
53+
54+
double percentageChange = ((endPrice - startPrice) / startPrice) * 100;
55+
String trendType = determineTrendType(percentageChange);
56+
57+
dailyTrends.add(new DailyTrend(entry.getKey(), trendType, percentageChange));
58+
}
59+
60+
return dailyTrends;
61+
}
62+
63+
private String determineTrendType(double percentageChange) {
64+
if (percentageChange > 2.0) return "UP";
65+
if (percentageChange < -2.0) return "DOWN";
66+
return "STABLE";
67+
}
68+
69+
70+
private List<Trend> calculateCompositeTrends(List<DailyTrend> dailyTrends, String symbol) {
71+
List<Trend> trends = new ArrayList<>();
72+
73+
74+
if (dailyTrends.size() >= 3) {
75+
trends.add(new Trend("SHORT_TERM",
76+
calculateTrendDescription(dailyTrends.subList(0, Math.min(3, dailyTrends.size()))), symbol));
77+
}
78+
79+
80+
if (dailyTrends.size() >= 7) {
81+
trends.add(new Trend("MID_TERM",
82+
calculateTrendDescription(dailyTrends.subList(0, Math.min(7, dailyTrends.size()))), symbol));
83+
}
84+
85+
86+
trends.add(new Trend("LONG_TERM", calculateTrendDescription(dailyTrends), symbol));
87+
88+
return trends;
89+
}
90+
91+
92+
private String calculateTrendDescription(List<DailyTrend> dailyTrends) {
93+
94+
long upCount = dailyTrends.stream().filter(d -> d.getTrendType().equals("UP")).count();
95+
long downCount = dailyTrends.stream().filter(d -> d.getTrendType().equals("DOWN")).count();
96+
97+
if (upCount > downCount) return "UP";
98+
if (downCount > upCount) return "DOWN";
99+
return "STABLE";
100+
}
101+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.prgrms.ijuju.domain.article.component;
2+
3+
import com.prgrms.ijuju.domain.article.data.Trend;
4+
import com.prgrms.ijuju.domain.stock.mid.entity.MidStockPrice;
5+
import org.springframework.stereotype.Component;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
@Component
11+
public class MidTrendAnalyzer {
12+
13+
public List<Trend> analyzeTrends(List<MidStockPrice> prices, String midName) {
14+
List<Trend> trends = new ArrayList<>();
15+
16+
// 3์ผ ๊ธฐ์ค€
17+
trends.add(new Trend("SHORT_TERM", calculateTrend(prices, 3), midName));
18+
19+
// 1์ฃผ ๊ธฐ์ค€
20+
trends.add(new Trend("MID_TERM", calculateTrend(prices, 7), midName));
21+
22+
// 2์ฃผ ๊ธฐ์ค€
23+
trends.add(new Trend("LONG_TERM", calculateTrend(prices, 14), midName));
24+
25+
return trends;
26+
}
27+
28+
private String calculateTrend(List<MidStockPrice> prices, int days) {
29+
if (prices.size() < days) return "INSUFFICIENT_DATA";
30+
31+
double startPrice = prices.get(prices.size() - days).getAvgPrice(); // ์‹œ์ž‘ ๊ฐ€๊ฒฉ
32+
double endPrice = prices.get(prices.size() - 1).getAvgPrice(); // ์ข…๋ฃŒ ๊ฐ€๊ฒฉ
33+
double percentageChange = ((endPrice - startPrice) / startPrice) * 100;
34+
35+
if (percentageChange > 2.0) return "UP";
36+
if (percentageChange < -2.0) return "DOWN";
37+
return "STABLE";
38+
}
39+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.prgrms.ijuju.domain.article.contant;
2+
3+
public enum DataType {
4+
ADVANCED, MID
5+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.prgrms.ijuju.domain.article.controller;
2+
3+
import com.prgrms.ijuju.domain.article.scheduler.ArticleScheduler;
4+
import com.prgrms.ijuju.domain.article.service.ArticleService;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.web.bind.annotation.*;
8+
import java.util.List;
9+
import com.prgrms.ijuju.domain.article.entity.Article;
10+
import com.prgrms.ijuju.domain.article.contant.DataType;
11+
12+
13+
14+
15+
@RestController
16+
@RequestMapping("/api/v1/articles")
17+
@RequiredArgsConstructor
18+
public class ArticleController {
19+
20+
private final ArticleService articleService;
21+
private final ArticleScheduler articleScheduler;
22+
23+
24+
@GetMapping("/{type}")
25+
public ResponseEntity<List<Article>> getArticlesByType(@PathVariable DataType type) {
26+
List<Article> articles = articleService.findArticlesByType(type);
27+
return ResponseEntity.ok(articles);
28+
}
29+
30+
31+
@GetMapping("/detail/{id}")
32+
public ResponseEntity<Article> getArticleById(@PathVariable Long id) {
33+
Article article = articleService.findArticleById(id);
34+
return ResponseEntity.ok(article);
35+
}
36+
37+
//๋””๋ฒ„๊น… ์šฉ๋„
38+
@GetMapping
39+
public ResponseEntity<List<Article>> getAllArticles() {
40+
List<Article> articles = articleService.findAllArticles();
41+
return ResponseEntity.ok(articles);
42+
}
43+
44+
//๋””๋ฒ„๊น… ์šฉ๋„
45+
@PostMapping("/manage-articles")
46+
public ResponseEntity<String> executeManageArticlesScheduler() {
47+
articleScheduler.manageArticles();
48+
return ResponseEntity.ok("์Šค์ผ€์ฅด๋Ÿฌ ๊ธฐ๋Šฅ์ด ๊ฐ•์ œ๋กœ ์‹คํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
49+
}
50+
}

0 commit comments

Comments
ย (0)