Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
# Conflicts:
#	.github/workflows/deploy.yml
#	Dockerfile
  • Loading branch information
deveunhwa committed Dec 9, 2024
2 parents 3e110dc + f97655b commit 8c0b0c7
Show file tree
Hide file tree
Showing 378 changed files with 20,066 additions and 428 deletions.
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ out/
### VS Code ###
.vscode/

### H2 DB file ###
# Ignore H2 database files
*.mv.db
*.trace.db
*.trace.db

#secret yml#
application-secret.yml
/src/main/resources/firebase/firebase_service_key.json
81 changes: 80 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,80 @@
# WEB1_2_Child-Learn_BE
# ์•„์ด์ฃผ์ฃผ ![์•„์ด์ฃผ์ฃผ 3](https://github.com/user-attachments/assets/89cd492b-92fe-46ef-b7f2-319e8df4c400)

![ํ”„๋กœ์ ํŠธ์ด๋ฏธ์ง€](https://github.com/user-attachments/assets/6e0bdf74-a374-4c70-952d-fc22e0ba3413)

## ๐Ÿ€ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ
์•„์ด์ฃผ์ฃผ๋Š” ์ดˆ๋“ฑํ•™์ƒ๋“ค์ด ๋ˆ๊ณผ ํˆฌ์ž์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์„ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋œ ๋ชจ์˜ํˆฌ์ž ํ•™์Šต ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.

[๐Ÿ”— ๊ธฐํš์„œ](https://www.notion.so/13f336d06fda80d4a0dfc9e9ac30e96b?pvs=4)
[๐Ÿ”— ๋””์ž์ธ](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)
[๐Ÿ”— ํ”„๋ก ํŠธ ๊นƒํ—ˆ๋ธŒ](https://github.com/prgrms-web-devcourse-final-project/WEB1_2_Child-Learn_FE)
[๐Ÿ”— ๋ฐฑ์—”๋“œ ๊นƒํ—ˆ๋ธŒ](https://github.com/prgrms-web-devcourse-final-project/WEB1_2_Child-Learn_BE)
[๐Ÿ”— ์•„์ด์ฃผ์ฃผ ๋ฐ”๋กœ๊ฐ€๊ธฐ](http://ijuju.site)

### ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ : 2024/11/18 ~ 2024/12/09

<br>


## ๐Ÿ€ ์ฃผ์š” ๊ธฐ๋Šฅ
> **์ฃผ์‹ ๊ทธ๋ž˜ํ”„**
- **๊ทธ๋ž˜ํ”„ ๋ฐ ๋ฐ์ดํ„ฐ ์ œ๊ณต:** ์ข…๋ชฉ๋ณ„ ํˆฌ์ž ๊ทธ๋ž˜ํ”„์™€ ๋น„์œ ์  ์„ค๋ช…์ด ๋‹ด๊ธด ๋‰ด์Šค๋ ˆํ„ฐ ์ œ๊ณต
- **AI ๋งž์ถคํ˜• ์ •๋ณด:** API๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ๋ฐ ๋งž์ถคํ˜• ๋‰ด์Šค ์•„ํ‹ฐํด ์ œ๊ณต
- **๋žœ๋ค์„ฑ๊ณผ ํ˜„์‹ค์„ฑ:** ๋žœ๋ค ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ์‹ค์ œ ๊ฒฝ์ œ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ผํ•ฉํ•ด ์žฌ๋ฏธ์žˆ๊ณ  ํ˜„์‹ค๊ฐ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„ ๋ณ€ํ™” ์ œ๊ณต

> **๋ฏธ๋‹ˆ๊ฒŒ์ž„**
์•„์ด๋“ค์˜ ํฅ๋ฏธ๋ฅผ ์œ ๋ฐœํ•˜๊ณ , ํ•™์Šต ํšจ๊ณผ๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๋ฏธ๋‹ˆ๊ฒŒ์ž„
- **์นด๋“œ ๋’ค์ง‘๊ธฐ**: ํˆฌ์ž ๊ด€๋ จ์šฉ์–ด๋ฅผ ๊ฒŒ์ž„์œผ๋กœ ๊ฐœ๋… ์ดํ•ด.
- **๊ธˆ์œต ํ€ด์ฆˆ:** ๋ˆ, ์ €์ถ•, ํˆฌ์ž ๊ด€๋ จ ํ€ด์ฆˆ๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ ๊ฐœ๋… ์ดํ•ด.
- **๋กœ๋˜:** ๊ฐ„๋‹จํ•œ ํ™•๋ฅ  ๊ฒŒ์ž„์œผ๋กœ ํˆฌ์ž์™€ ์œ„ํ—˜์˜ ๊ฐœ๋… ์ดํ•ด.

> **์ƒ์ **
- ๊ฒŒ์ž„ ๋ฐ ์ฃผ์‹ํˆฌ์ž๋ฅผ ํ†ตํ•˜์—ฌ ํš๋“ํ•œ ํฌ์ธํŠธ๋กœ ์ƒ์ ๊ธฐ๋Šฅ ์ œ๊ณต.
- ์ƒ์ ์—์„œ ์ž์‹ ๋งŒ์˜ ์•„๋ฐ”ํƒ€๋ฅผ ๊พธ๋ฐ€ ์ˆ˜ ์žˆ๋Š” ์•„์ดํ…œ ์ œ๊ณต.
- ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์•„์ดํ…œ์œผ๋กœ ํฅ๋ฏธ ์ œ๊ณต.

<br>

## ๐Ÿ€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ
### ํ†ตํ•ฉ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜
![ํ†ตํ•ฉ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜](https://github.com/user-attachments/assets/f6ddd958-6a68-4305-84c3-3e6f8098633f)

<br>

## ๐Ÿ€ ๊ฐœ๋ฐœ ๋ฌธ์„œ
<details>
<summary>ERD</summary>
</details>
<details>
<summary>์•„ํ‚คํ…์ฒ˜</summary>

![๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์•„ํ‚คํ…์ฒ˜](https://github.com/user-attachments/assets/f96d2c88-223c-47b4-a673-ac613be39063)

</details>
<details>
<summary>์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ์„œ</summary>

[๐Ÿ”— ์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ์„œ](https://foggy-move-190.notion.site/67c1e522ca8047d98094580d9bdc8f87?pvs=74)
</details>
<details>
<summary>API ๋ช…์„ธ์„œ</summary>

[๐Ÿ”— API ๋ช…์„ธ์„œ](https://foggy-move-190.notion.site/API-b44b55ec93c9478c9a25c9f75150b773?pvs=73)
</details>

## ๐Ÿ€ ํŒ€ ์†Œ๊ฐœ

### FRONTEND
| ๐Ÿ‘‘ ์ดํฌ์ฃผ | ๐Ÿ“‹ ๋ฐ•์šฐํ˜„ | ๋ฅ˜๋ฏผ์ฃผ |
|:----------------------------------------------------------:|:----------------------------------------------------------:|:-------------------------------------:|
| FE TeamLeader | PM | Git_Admin |
| [tree0000](https://github.com/tree0000) | [hjlee2778](https://github.com/hjlee2778) | [minij02](https://github.com/minij02) |
| ![](https://avatars.githubusercontent.com/u/141895600?v=4) | ![](https://avatars.githubusercontent.com/u/144092849?v=4) | ![](https://avatars.githubusercontent.com/u/135093109?v=4)|

### BACKEND
| ๐Ÿ‘‘ ์ž„์ง€์€ | ์‹ ์€ํ™” | ์ตœ์žฌํ˜• | ์ด์ˆ˜๋นˆ | ๋ฐ•์ฐฌ์„œ |
|:---------------------------------:|:-----------------------------------------:|:--------------------------------:|:---------------------------------------:|:---------------------------------------:|
| BE TeamLeader & AWS_Admin | Git_Admin | Developer | Developer | Developer |
| [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) |
| ![](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) |
50 changes: 48 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,73 @@ repositories {
}

dependencies {
// jpa
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// SMTP
implementation 'org.springframework.boot:spring-boot-starter-mail'
// security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'

// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', 'io.jsonwebtoken:jjwt-jackson:0.12.3'


// validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

// spring web
implementation 'org.springframework.boot:spring-boot-starter-web'

// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// devtools
developmentOnly 'org.springframework.boot:spring-boot-devtools'

// DB
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
implementation 'mysql:mysql-connector-java:8.0.33'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// Querydsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

// WebSocket + STOMP
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// MongoDB
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

//OAuth2.0
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

// Spring Cache - caffeine
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine'
}

tasks.named('test') {
useJUnitPlatform()
}

tasks.withType(JavaExec) {
jvmArgs += ['--add-opens', 'java.base/java.io=ALL-UNNAMED']
}

test {
jvmArgs += ['--add-opens', 'java.base/java.io=ALL-UNNAMED']
}
4 changes: 4 additions & 0 deletions src/main/java/com/prgrms/ijuju/IjujuApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@EnableJpaAuditing
@SpringBootApplication
public class IjujuApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.prgrms.ijuju.domain.article.component;

import com.prgrms.ijuju.domain.article.data.DailyTrend;
import com.prgrms.ijuju.domain.article.data.Trend;
import com.prgrms.ijuju.domain.stock.adv.advstock.entity.AdvStock;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Adv ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” timeStamp ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ, ํ•œ์‹œ๊ฐ„ ๋ด‰์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค
* ๋ฐ์ดํ„ฐ ๋ถ„์„์„ ์œ„ํ•ด์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ "ํ•˜๋ฃจ" ๋‹จ์œ„๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค
*/
@Component
public class AdvTrendAnalyzer {


public List<Trend> analyzeTrends(AdvStock advStock) {
Map<LocalDate, List<Double>> groupedData = groupByDate(advStock.getTimestamps(), advStock.getClosePrices());

List<DailyTrend> dailyTrends = calculateDailyTrends(groupedData);

return calculateCompositeTrends(dailyTrends, advStock.getSymbol());
}

// ํ•œ ์‹œ๊ฐ„ ๋‹จ์œ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ผ ๋‹จ์œ„๋กœ ๋ฌถ์Œ
// AdvStock ์€ timeStamps ๋กœ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๊ธฐ์—, LocalData ๋กœ ๋ณ€ํ™˜ํ•  ๊ณผ์ •์ด ํ•„์š”ํ•˜๊ธฐ์— ์ƒ์„ฑ๋œ ๋ฉ”์†Œ๋“œ ์ž…๋‹ˆ๋‹ค
private Map<LocalDate, List<Double>> groupByDate(List<Long> timestamps, List<Double> closePrices) {
Map<LocalDate, List<Double>> groupedData = new HashMap<>();

for (int i = 0; i < timestamps.size(); i++) {
LocalDate date = Instant.ofEpochMilli(timestamps.get(i)).atZone(ZoneId.systemDefault()).toLocalDate();
groupedData.computeIfAbsent(date, k -> new ArrayList<>()).add(closePrices.get(i));
}

return groupedData;
}


private List<DailyTrend> calculateDailyTrends(Map<LocalDate, List<Double>> groupedData) {
List<DailyTrend> dailyTrends = new ArrayList<>();

for (Map.Entry<LocalDate, List<Double>> entry : groupedData.entrySet()) {
List<Double> dailyPrices = entry.getValue();
double startPrice = dailyPrices.get(0);
double endPrice = dailyPrices.get(dailyPrices.size() - 1);

double percentageChange = ((endPrice - startPrice) / startPrice) * 100;
String trendType = determineTrendType(percentageChange);

dailyTrends.add(new DailyTrend(entry.getKey(), trendType, percentageChange));
}

return dailyTrends;
}

private String determineTrendType(double percentageChange) {
if (percentageChange > 2.0) return "UP";
if (percentageChange < -2.0) return "DOWN";
return "STABLE";
}


private List<Trend> calculateCompositeTrends(List<DailyTrend> dailyTrends, String symbol) {
List<Trend> trends = new ArrayList<>();


if (dailyTrends.size() >= 3) {
trends.add(new Trend("SHORT_TERM",
calculateTrendDescription(dailyTrends.subList(0, Math.min(3, dailyTrends.size()))), symbol));
}


if (dailyTrends.size() >= 7) {
trends.add(new Trend("MID_TERM",
calculateTrendDescription(dailyTrends.subList(0, Math.min(7, dailyTrends.size()))), symbol));
}


trends.add(new Trend("LONG_TERM", calculateTrendDescription(dailyTrends), symbol));

return trends;
}


private String calculateTrendDescription(List<DailyTrend> dailyTrends) {

long upCount = dailyTrends.stream().filter(d -> d.getTrendType().equals("UP")).count();
long downCount = dailyTrends.stream().filter(d -> d.getTrendType().equals("DOWN")).count();

if (upCount > downCount) return "UP";
if (downCount > upCount) return "DOWN";
return "STABLE";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.prgrms.ijuju.domain.article.component;

import com.prgrms.ijuju.domain.article.data.Trend;
import com.prgrms.ijuju.domain.stock.mid.entity.MidStockPrice;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MidTrendAnalyzer {

public List<Trend> analyzeTrends(List<MidStockPrice> prices, String midName) {
List<Trend> trends = new ArrayList<>();

// 3์ผ ๊ธฐ์ค€
trends.add(new Trend("SHORT_TERM", calculateTrend(prices, 3), midName));

// 1์ฃผ ๊ธฐ์ค€
trends.add(new Trend("MID_TERM", calculateTrend(prices, 7), midName));

// 2์ฃผ ๊ธฐ์ค€
trends.add(new Trend("LONG_TERM", calculateTrend(prices, 14), midName));

return trends;
}

private String calculateTrend(List<MidStockPrice> prices, int days) {
if (prices.size() < days) return "INSUFFICIENT_DATA";

double startPrice = prices.get(prices.size() - days).getAvgPrice(); // ์‹œ์ž‘ ๊ฐ€๊ฒฉ
double endPrice = prices.get(prices.size() - 1).getAvgPrice(); // ์ข…๋ฃŒ ๊ฐ€๊ฒฉ
double percentageChange = ((endPrice - startPrice) / startPrice) * 100;

if (percentageChange > 2.0) return "UP";
if (percentageChange < -2.0) return "DOWN";
return "STABLE";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.prgrms.ijuju.domain.article.contant;

public enum DataType {
ADVANCED, MID
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.prgrms.ijuju.domain.article.controller;

import com.prgrms.ijuju.domain.article.scheduler.ArticleScheduler;
import com.prgrms.ijuju.domain.article.service.ArticleService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import com.prgrms.ijuju.domain.article.entity.Article;
import com.prgrms.ijuju.domain.article.contant.DataType;




@RestController
@RequestMapping("/api/v1/articles")
@RequiredArgsConstructor
public class ArticleController {

private final ArticleService articleService;
private final ArticleScheduler articleScheduler;


@GetMapping("/{type}")
public ResponseEntity<List<Article>> getArticlesByType(@PathVariable DataType type) {
List<Article> articles = articleService.findArticlesByType(type);
return ResponseEntity.ok(articles);
}


@GetMapping("/detail/{id}")
public ResponseEntity<Article> getArticleById(@PathVariable Long id) {
Article article = articleService.findArticleById(id);
return ResponseEntity.ok(article);
}

//๋””๋ฒ„๊น… ์šฉ๋„
@GetMapping
public ResponseEntity<List<Article>> getAllArticles() {
List<Article> articles = articleService.findAllArticles();
return ResponseEntity.ok(articles);
}

//๋””๋ฒ„๊น… ์šฉ๋„
@PostMapping("/manage-articles")
public ResponseEntity<String> executeManageArticlesScheduler() {
articleScheduler.manageArticles();
return ResponseEntity.ok("์Šค์ผ€์ฅด๋Ÿฌ ๊ธฐ๋Šฅ์ด ๊ฐ•์ œ๋กœ ์‹คํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
}
}
Loading

0 comments on commit 8c0b0c7

Please sign in to comment.