From 635f76f9b7b9531909a92526e60b37bf3db864dc Mon Sep 17 00:00:00 2001
From: dannysir <48199716+dannysir@users.noreply.github.com>
Date: Tue, 3 Dec 2024 11:23:13 +0900
Subject: [PATCH 1/9] Update README.md
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6d2c4d7..345078e 100644
--- a/README.md
+++ b/README.md
@@ -52,12 +52,14 @@
- 일별, 실시간 시세를 확인할 수 있습니다.
- 매수, 매도 요청을 할 수 있습니다.
-### 주식 차트
+### 주식 차트
![화면 기록 2024-11-28 오후 6 40 30](https://github.com/user-attachments/assets/6d36b0d9-2db2-4018-a7f3-2c12fb586fd0)
- 일, 주, 월, 년 단위로 주식 차트를 확인할 수 있습니다.
- 이동평균선 정보를 활용해 해당 주식의 추이를 더 자세히 확인할 수 있습니다.
- 라이브러리를 사용하지 않고 canvas를 활용해 직접 구현했습니다.
+- [라이브러리 없이 구현한 이유.](https://github.com/boostcampwm-2024/web16-JuGa/wiki/라이브러리-없이-차트를-직접-구현한-이유)
+
### 마이페이지
![juga_mypage](https://github.com/user-attachments/assets/8cdfa089-ac26-40a0-8d19-7a56a0f3c6e7)
From 1acdd10102e18018df7428821a1575de8a93ec53 Mon Sep 17 00:00:00 2001
From: Dongwoo Ko <68095803+dongree@users.noreply.github.com>
Date: Tue, 3 Dec 2024 12:57:58 +0900
Subject: [PATCH 2/9] Update README.md
---
README.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 345078e..52f30c2 100644
--- a/README.md
+++ b/README.md
@@ -39,21 +39,21 @@
### 메인 페이지
-![juga_main](https://github.com/user-attachments/assets/abb04197-ae88-4877-be53-2ca71ad3e57b)
+
- 메인 페이지에서 코스피, 코스닥 등 실시간 주가 지수를 확인할 수 있습니다.
- 상승률/하락률 TOP5 종목을 주가지수 별로 확인할 수 있습니다.
- 오늘 실시간 주요 뉴스를 확인할 수 있습니다.
### 주식 상세 페이지
-![juga_detail](https://github.com/user-attachments/assets/14ed36ae-085e-4899-a314-8ece85236a55)
+
- 해당 주식에 대한 정보를 차트로 확인할 수 있습니다.
- 일별, 실시간 시세를 확인할 수 있습니다.
- 매수, 매도 요청을 할 수 있습니다.
### 주식 차트
-![화면 기록 2024-11-28 오후 6 40 30](https://github.com/user-attachments/assets/6d36b0d9-2db2-4018-a7f3-2c12fb586fd0)
+
- 일, 주, 월, 년 단위로 주식 차트를 확인할 수 있습니다.
- 이동평균선 정보를 활용해 해당 주식의 추이를 더 자세히 확인할 수 있습니다.
@@ -62,7 +62,7 @@
### 마이페이지
-![juga_mypage](https://github.com/user-attachments/assets/8cdfa089-ac26-40a0-8d19-7a56a0f3c6e7)
+
- 현재 자산 현황, 투자 성과를 확인할 수 있습니다.
- 자신이 매수한 주식 정보들을 확인할 수 있습니다.
@@ -72,14 +72,14 @@
### 로그인
-![image (14)](https://github.com/user-attachments/assets/9968ef08-cbf8-41fd-bfdc-8ca25dd8d80c)
+
- 로그인 모달창에서 로그인을 할 수 있습니다.
- 카카오 oAuth 로그인으로 간편하게 로그인할 수 있습니다.
### 랭킹
-![image (15)](https://github.com/user-attachments/assets/251821a9-63d9-4f23-9178-2f8f3d8c608d)
+
- 하루 단위로 랭킹이 갱신됩니다.
- 수익률순, 자산순을 기준으로 랭킹을 확인할 수 있습니다.
From fcf2cb5b85dd86d3692076ab24468c5577f4bce6 Mon Sep 17 00:00:00 2001
From: jinddings
Date: Tue, 3 Dec 2024 18:01:42 +0900
Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=94=A7=20fix=20:=20=EC=9B=B9=EC=86=8C?=
=?UTF-8?q?=EC=BC=93=20=EC=97=B0=EA=B2=B0=20=EC=B4=88=EA=B3=BC=EC=8B=9C=20?=
=?UTF-8?q?error=20=EB=B0=9C=EC=83=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BE/src/common/websocket/base-socket.domain-service.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/BE/src/common/websocket/base-socket.domain-service.ts b/BE/src/common/websocket/base-socket.domain-service.ts
index 527bf9f..2b3f9f0 100644
--- a/BE/src/common/websocket/base-socket.domain-service.ts
+++ b/BE/src/common/websocket/base-socket.domain-service.ts
@@ -45,11 +45,18 @@ export class BaseSocketDomainService implements OnModuleInit {
if (data.length < 2) {
const json = JSON.parse(data[0]);
- if (json.body)
+ if (json.body) {
this.logger.log(
`한국투자증권 웹소켓 연결: ${json.body.msg1}`,
json.header.tr_id,
);
+
+ if (json.body.msg1 === 'MAX SUBSCRIBE OVER') {
+ throw new InternalServerErrorException(
+ '한국투자증권 웹소켓 연결: MAX SUBSCRIBE OVER',
+ );
+ }
+ }
if (json.header.tr_id === 'PINGPONG')
this.socket.pong(JSON.stringify(json));
return;
From 6608f7e24b8c6722fe204dc332a7d6e8be302e07 Mon Sep 17 00:00:00 2001
From: jinddings
Date: Tue, 3 Dec 2024 18:34:43 +0900
Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=9A=91=20!HOTFIX=20:=20socket=20gate?=
=?UTF-8?q?=20way=20filter=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../filters/websocket-exception.filter.ts | 39 +++++++++++++++++++
BE/src/common/websocket/socket.gateway.ts | 4 +-
2 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 BE/src/common/filters/websocket-exception.filter.ts
diff --git a/BE/src/common/filters/websocket-exception.filter.ts b/BE/src/common/filters/websocket-exception.filter.ts
new file mode 100644
index 0000000..349bfbd
--- /dev/null
+++ b/BE/src/common/filters/websocket-exception.filter.ts
@@ -0,0 +1,39 @@
+import {
+ ArgumentsHost,
+ Catch,
+ ExceptionFilter,
+ HttpStatus,
+ Logger,
+ InternalServerErrorException,
+} from '@nestjs/common';
+
+import { Request, Response } from 'express';
+
+@Catch(InternalServerErrorException)
+export class WebSocketExceptionFilter implements ExceptionFilter {
+ private readonly logger = new Logger(WebSocketExceptionFilter.name);
+
+ catch(exception: InternalServerErrorException, host: ArgumentsHost) {
+ const ctx = host.switchToHttp();
+
+ const request = ctx.getRequest();
+ const response = ctx.getResponse();
+
+ const status = HttpStatus.INTERNAL_SERVER_ERROR;
+
+ const { message } = exception;
+
+ const errorResponse = {
+ statusCode: status,
+ message,
+ timestamp: new Date().toISOString(),
+ path: request.url,
+ };
+
+ this.logger.error(
+ `[${request.method}] ${request.url} - Status: ${status} - Error: ${exception.message}`,
+ );
+
+ response.status(status).json(errorResponse);
+ }
+}
diff --git a/BE/src/common/websocket/socket.gateway.ts b/BE/src/common/websocket/socket.gateway.ts
index d533c3f..b898fda 100644
--- a/BE/src/common/websocket/socket.gateway.ts
+++ b/BE/src/common/websocket/socket.gateway.ts
@@ -1,8 +1,10 @@
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Server } from 'socket.io';
-import { Logger } from '@nestjs/common';
+import { Logger, UseFilters } from '@nestjs/common';
+import { WebSocketExceptionFilter } from '../filters/websocket-exception.filter';
@WebSocketGateway({ namespace: 'socket', cors: { origin: '*' } })
+@UseFilters(new WebSocketExceptionFilter())
export class SocketGateway {
@WebSocketServer()
private server: Server;
From b7559f7d95deb0502f6b83bb33768df2d6ce6727 Mon Sep 17 00:00:00 2001
From: jinddings
Date: Tue, 3 Dec 2024 18:46:13 +0900
Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=94=A7=20fix=20:=20Websocket=20?=
=?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=EB=A1=9C=20=EB=B3=80?=
=?UTF-8?q?=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../filters/websocket-exception.filter.ts | 39 +++++++------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/BE/src/common/filters/websocket-exception.filter.ts b/BE/src/common/filters/websocket-exception.filter.ts
index 349bfbd..9a81ccd 100644
--- a/BE/src/common/filters/websocket-exception.filter.ts
+++ b/BE/src/common/filters/websocket-exception.filter.ts
@@ -1,39 +1,28 @@
-import {
- ArgumentsHost,
- Catch,
- ExceptionFilter,
- HttpStatus,
- Logger,
- InternalServerErrorException,
-} from '@nestjs/common';
+import { ArgumentsHost, Catch, ExceptionFilter, Logger } from '@nestjs/common';
+import { WsException } from '@nestjs/websockets';
-import { Request, Response } from 'express';
-
-@Catch(InternalServerErrorException)
+@Catch()
export class WebSocketExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger(WebSocketExceptionFilter.name);
- catch(exception: InternalServerErrorException, host: ArgumentsHost) {
- const ctx = host.switchToHttp();
-
- const request = ctx.getRequest();
- const response = ctx.getResponse();
-
- const status = HttpStatus.INTERNAL_SERVER_ERROR;
+ catch(exception: Error, host: ArgumentsHost) {
+ const ctx = host.switchToWs();
+ const client = ctx.getClient();
- const { message } = exception;
+ const message =
+ exception instanceof WsException
+ ? exception.message
+ : 'Internal WebSocket Error';
const errorResponse = {
- statusCode: status,
+ event: 'error',
message,
timestamp: new Date().toISOString(),
- path: request.url,
};
- this.logger.error(
- `[${request.method}] ${request.url} - Status: ${status} - Error: ${exception.message}`,
- );
+ this.logger.error(`WebSocket Error: ${message}`, exception.stack);
- response.status(status).json(errorResponse);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ client.send(JSON.stringify(errorResponse));
}
}
From 3b89940f98c954fb0d674b9cb465a49cd18b3f8b Mon Sep 17 00:00:00 2001
From: JIN <80706216+uuuo3o@users.noreply.github.com>
Date: Tue, 3 Dec 2024 19:40:28 +0900
Subject: [PATCH 6/9] Update README.md
---
README.md | 26 --------------------------
1 file changed, 26 deletions(-)
diff --git a/README.md b/README.md
index 52f30c2..a366266 100644
--- a/README.md
+++ b/README.md
@@ -59,32 +59,6 @@
- 이동평균선 정보를 활용해 해당 주식의 추이를 더 자세히 확인할 수 있습니다.
- 라이브러리를 사용하지 않고 canvas를 활용해 직접 구현했습니다.
- [라이브러리 없이 구현한 이유.](https://github.com/boostcampwm-2024/web16-JuGa/wiki/라이브러리-없이-차트를-직접-구현한-이유)
-
-
-### 마이페이지
-
-
-- 현재 자산 현황, 투자 성과를 확인할 수 있습니다.
-- 자신이 매수한 주식 정보들을 확인할 수 있습니다.
-- 주문 요청 현황 탭에서 주문 요청한 주식들을 확인하고 요청을 취소할 수 있습니다.
-- 즐겨찾기 탭에서 주식 상세 페이지에서 좋아요한 주식들을 확인할 수 있습니다.
-- 내 정보 탭에서 자신의 닉네임을 변경할 수 있습니다.
-
-
-### 로그인
-
-
-- 로그인 모달창에서 로그인을 할 수 있습니다.
-- 카카오 oAuth 로그인으로 간편하게 로그인할 수 있습니다.
-
-
-### 랭킹
-
-
-- 하루 단위로 랭킹이 갱신됩니다.
-- 수익률순, 자산순을 기준으로 랭킹을 확인할 수 있습니다.
-- 자신의 오늘 랭킹을 확인할 수 있습니다.
-
## 🏛️ 소프트웨어 아키텍처
From 799f87c6c4a526387572fe7511a7bbd98bfbd1fd Mon Sep 17 00:00:00 2001
From: jinddings
Date: Tue, 3 Dec 2024 19:44:43 +0900
Subject: [PATCH 7/9] =?UTF-8?q?=F0=9F=94=A7=20fix=20:=20web=20socket=20err?=
=?UTF-8?q?or=20=ED=95=84=ED=84=B0=20=EC=82=AD=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../filters/websocket-exception.filter.ts | 28 -------------------
.../websocket/base-socket.domain-service.ts | 6 ----
BE/src/common/websocket/socket.gateway.ts | 4 +--
.../history/stock-trade-history.service.ts | 9 ++++--
4 files changed, 8 insertions(+), 39 deletions(-)
delete mode 100644 BE/src/common/filters/websocket-exception.filter.ts
diff --git a/BE/src/common/filters/websocket-exception.filter.ts b/BE/src/common/filters/websocket-exception.filter.ts
deleted file mode 100644
index 9a81ccd..0000000
--- a/BE/src/common/filters/websocket-exception.filter.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { ArgumentsHost, Catch, ExceptionFilter, Logger } from '@nestjs/common';
-import { WsException } from '@nestjs/websockets';
-
-@Catch()
-export class WebSocketExceptionFilter implements ExceptionFilter {
- private readonly logger = new Logger(WebSocketExceptionFilter.name);
-
- catch(exception: Error, host: ArgumentsHost) {
- const ctx = host.switchToWs();
- const client = ctx.getClient();
-
- const message =
- exception instanceof WsException
- ? exception.message
- : 'Internal WebSocket Error';
-
- const errorResponse = {
- event: 'error',
- message,
- timestamp: new Date().toISOString(),
- };
-
- this.logger.error(`WebSocket Error: ${message}`, exception.stack);
-
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- client.send(JSON.stringify(errorResponse));
- }
-}
diff --git a/BE/src/common/websocket/base-socket.domain-service.ts b/BE/src/common/websocket/base-socket.domain-service.ts
index 2b3f9f0..5f77220 100644
--- a/BE/src/common/websocket/base-socket.domain-service.ts
+++ b/BE/src/common/websocket/base-socket.domain-service.ts
@@ -50,12 +50,6 @@ export class BaseSocketDomainService implements OnModuleInit {
`한국투자증권 웹소켓 연결: ${json.body.msg1}`,
json.header.tr_id,
);
-
- if (json.body.msg1 === 'MAX SUBSCRIBE OVER') {
- throw new InternalServerErrorException(
- '한국투자증권 웹소켓 연결: MAX SUBSCRIBE OVER',
- );
- }
}
if (json.header.tr_id === 'PINGPONG')
this.socket.pong(JSON.stringify(json));
diff --git a/BE/src/common/websocket/socket.gateway.ts b/BE/src/common/websocket/socket.gateway.ts
index b898fda..d533c3f 100644
--- a/BE/src/common/websocket/socket.gateway.ts
+++ b/BE/src/common/websocket/socket.gateway.ts
@@ -1,10 +1,8 @@
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Server } from 'socket.io';
-import { Logger, UseFilters } from '@nestjs/common';
-import { WebSocketExceptionFilter } from '../filters/websocket-exception.filter';
+import { Logger } from '@nestjs/common';
@WebSocketGateway({ namespace: 'socket', cors: { origin: '*' } })
-@UseFilters(new WebSocketExceptionFilter())
export class SocketGateway {
@WebSocketServer()
private server: Server;
diff --git a/BE/src/stock/trade/history/stock-trade-history.service.ts b/BE/src/stock/trade/history/stock-trade-history.service.ts
index 8ef3b26..7fa7e60 100644
--- a/BE/src/stock/trade/history/stock-trade-history.service.ts
+++ b/BE/src/stock/trade/history/stock-trade-history.service.ts
@@ -1,4 +1,4 @@
-import { Injectable } from '@nestjs/common';
+import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { KoreaInvestmentDomainService } from '../../../common/koreaInvestment/korea-investment.domain-service';
import { InquireCCNLApiResponse } from './interface/Inquire-ccnl.interface';
import { TodayStockTradeHistoryOutputDto } from './dto/today-stock-trade-history-output.dto';
@@ -35,7 +35,12 @@ export class StockTradeHistoryService {
queryParams,
);
- this.stockPriceSocketService.subscribeByCode(stockCode);
+ try {
+ this.stockPriceSocketService.subscribeByCode(stockCode);
+ } catch (e) {
+ throw new InternalServerErrorException(e);
+ }
+
return this.formatTodayStockTradeHistoryData(response.output);
}
From 6d70a3cb3f12c2ddaaf152d00acef36fb555ded8 Mon Sep 17 00:00:00 2001
From: sieun <147706431+sieunie@users.noreply.github.com>
Date: Tue, 3 Dec 2024 20:11:05 +0900
Subject: [PATCH 8/9] Update README.md
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index a366266..969d460 100644
--- a/README.md
+++ b/README.md
@@ -58,11 +58,14 @@
- 일, 주, 월, 년 단위로 주식 차트를 확인할 수 있습니다.
- 이동평균선 정보를 활용해 해당 주식의 추이를 더 자세히 확인할 수 있습니다.
- 라이브러리를 사용하지 않고 canvas를 활용해 직접 구현했습니다.
-- [라이브러리 없이 구현한 이유.](https://github.com/boostcampwm-2024/web16-JuGa/wiki/라이브러리-없이-차트를-직접-구현한-이유)
+- [라이브러리 없이 구현한 이유](https://github.com/boostcampwm-2024/web16-JuGa/wiki/라이브러리-없이-차트를-직접-구현한-이유)
## 🏛️ 소프트웨어 아키텍처
+- 한국투자증권 웹소켓은 한 계좌 당 41개의 종목에 대한 구독만을 유지할 수 있기 때문에, 최대한 많은 구독을 가능하게 하기 위한 방법으로 `Load Balancing`을 선택했습니다.
+- 서버의 각 컨테이너는 모두 다른 계좌로 연결되어 총 `41*3`개의 구독을 유지할 수 있습니다.
+- 추가로, redis의 pub/sub을 활용하여 서로 다른 서버로 요청이 들어오더라도 같은 종목에 대한 구독은 하나의 서버에서만 관리하도록 구현해 구독 자원을 최대한 절약하도록 했습니다.
## 🧑🏻 팀원 소개
| 🖥️ Web FE | ⚙️ Web BE | ⚙️ Web BE | 🖥️ Web FE | ⚙️ Web BE |
From 1b1f8fac8161d22bbd8d5c686863fccb751ef714 Mon Sep 17 00:00:00 2001
From: jinddings
Date: Tue, 3 Dec 2024 20:59:56 +0900
Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=9A=91=20!HOTFIX=20:=20=EB=A1=9C?=
=?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=90=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20?=
=?UTF-8?q?=EC=83=81=ED=83=9C=EC=97=90=EC=84=9C=20200=20status,=20isLogin?=
=?UTF-8?q?=20False=20=EB=A1=9C=20=EC=9D=91=EB=8B=B5=ED=95=98=EA=B2=8C=20?=
=?UTF-8?q?=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BE/src/auth/auth.controller.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/BE/src/auth/auth.controller.ts b/BE/src/auth/auth.controller.ts
index 88c7ad5..fbb629e 100644
--- a/BE/src/auth/auth.controller.ts
+++ b/BE/src/auth/auth.controller.ts
@@ -15,6 +15,7 @@ import { Request, Response } from 'express';
import { ConfigService } from '@nestjs/config';
import { AuthService } from './auth.service';
import { AuthCredentialsDto } from './dto/auth-credentials.dto';
+import { OptionalAuthGuard } from './optional-auth-guard';
@Controller('/api/auth')
export class AuthController {
@@ -83,13 +84,14 @@ export class AuthController {
@ApiOperation({ summary: '로그인 상태 확인 API' })
@Get('/check')
- @UseGuards(AuthGuard('jwt'))
+ @UseGuards(OptionalAuthGuard)
@ApiResponse({
status: 200,
description: '로그인 상태 조회 성공',
example: { isLogin: true },
})
- check() {
+ check(@Req() req: Request) {
+ if (!req.user) return { isLogin: false };
return { isLogin: true };
}