시스템아키텍처 완료.,
This commit is contained in:
parent
00e33342df
commit
48f711c4a9
@ -24,8 +24,8 @@ I'm AI 투자매니저 시스템의 전체 아키텍처를 정의하여 개발
|
|||||||
└─────────────────────┬───────────────────────────────────────────┘
|
└─────────────────────┬───────────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
┌─────────────────────▼───────────────────────────────────────────┐
|
┌─────────────────────▼───────────────────────────────────────────┐
|
||||||
│ React Frontend App │
|
│ AWS Lambda (React SSR) │
|
||||||
│ (S3 Static Hosting) │
|
│ + S3 정적 에셋 (js, css, images) │
|
||||||
└─────────────────────┬───────────────────────────────────────────┘
|
└─────────────────────┬───────────────────────────────────────────┘
|
||||||
│ API Calls
|
│ API Calls
|
||||||
┌─────────────────────▼───────────────────────────────────────────┐
|
┌─────────────────────▼───────────────────────────────────────────┐
|
||||||
@ -79,10 +79,12 @@ I'm AI 투자매니저 시스템의 전체 아키텍처를 정의하여 개발
|
|||||||
|
|
||||||
#### 3.1.1 기술 스택
|
#### 3.1.1 기술 스택
|
||||||
- **Framework**: React 18 + TypeScript
|
- **Framework**: React 18 + TypeScript
|
||||||
|
- **Rendering**: Server-Side Rendering (SSR) via Lambda
|
||||||
|
- **Static Assets**: S3 호스팅 (JS, CSS, Images)
|
||||||
- **State Management**: Zustand (가벼운 상태관리)
|
- **State Management**: Zustand (가벼운 상태관리)
|
||||||
- **Styling**: Tailwind CSS + shadcn/ui
|
- **Styling**: Tailwind CSS + shadcn/ui
|
||||||
- **Chart Library**: Chart.js + TradingView Widgets
|
- **Chart Library**: Chart.js + TradingView Widgets
|
||||||
- **Build Tool**: Vite
|
- **Build Tool**: Vite + Lambda Adapter
|
||||||
- **WebSocket**: Socket.IO Client
|
- **WebSocket**: Socket.IO Client
|
||||||
|
|
||||||
#### 3.1.2 컴포넌트 구조
|
#### 3.1.2 컴포넌트 구조
|
||||||
@ -106,12 +108,18 @@ src/
|
|||||||
- **반응형 디자인**: 모바일/데스크톱 대응
|
- **반응형 디자인**: 모바일/데스크톱 대응
|
||||||
- **캐싱 전략**: React Query로 데이터 캐싱
|
- **캐싱 전략**: React Query로 데이터 캐싱
|
||||||
- **성능 최적화**: Code Splitting, Lazy Loading
|
- **성능 최적화**: Code Splitting, Lazy Loading
|
||||||
|
- **SSR 최적화**: Lambda에서 초기 HTML 렌더링
|
||||||
|
- **하이브리드 배포**: 동적 페이지(Lambda) + 정적 에셋(S3)
|
||||||
|
|
||||||
### 3.2 API 계층 (AWS Lambda)
|
### 3.2 서버리스 계층 (AWS Lambda)
|
||||||
|
|
||||||
#### 3.2.1 Lambda 함수 구성
|
#### 3.2.1 Lambda 함수 구성
|
||||||
```
|
```
|
||||||
lambda-functions/
|
lambda-functions/
|
||||||
|
├── frontend-ssr/ # React SSR Lambda
|
||||||
|
│ ├── index.js # React SSR 핸들러
|
||||||
|
│ ├── package.json
|
||||||
|
│ └── dist/ # Vite 빌드 결과
|
||||||
├── main-api/ # 메인 페이지 API
|
├── main-api/ # 메인 페이지 API
|
||||||
│ ├── handler.py
|
│ ├── handler.py
|
||||||
│ └── requirements.txt
|
│ └── requirements.txt
|
||||||
@ -155,10 +163,11 @@ airflow/
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 3.3.2 데이터 파이프라인
|
#### 3.3.2 데이터 파이프라인
|
||||||
1. **데이터 수집 (매 5분)**: 업비트/야후파이낸스 API 호출
|
1. **데이터 수집 (1회/1분)**: 업비트/야후파이낸스 API 호출
|
||||||
2. **데이터 정규화**: 수집 데이터 표준화 및 검증
|
2. **실시간 데이터 수집**: 업비트: 웹소켓/야후파이낸스: 1회/1분
|
||||||
3. **AI 분석 (매 24시간)**: 수집된 데이터로 AI 분석 수행
|
3. **데이터 정규화**: 수집 데이터 표준화 및 검증
|
||||||
4. **결과 업로드**: 분석 결과를 JSON 형태로 S3 업로드
|
4. **AI 분석**: 수집된 데이터로 AI 분석 수행 - 정규 3시간에 한번, 트리거 발생시 즉시(목표가/손절가 도달 -> 새로운 기준 제시를 위함)
|
||||||
|
5. **결과 업로드**: 분석 결과를 JSON 형태로 S3 업로드
|
||||||
|
|
||||||
### 3.4 데이터베이스 설계
|
### 3.4 데이터베이스 설계
|
||||||
|
|
||||||
@ -168,72 +177,128 @@ airflow/
|
|||||||
|
|
||||||
#### 3.4.2 주요 테이블 구조
|
#### 3.4.2 주요 테이블 구조
|
||||||
```sql
|
```sql
|
||||||
-- 투자상품 기본정보
|
-- AI API 요청 정보
|
||||||
CREATE TABLE symbols (
|
CREATE TABLE public.ai_requests (
|
||||||
id SERIAL PRIMARY KEY,
|
request_id serial4 NOT NULL, -- 요청 KEY
|
||||||
symbol VARCHAR(20) UNIQUE NOT NULL,
|
invest_code varchar(10) NULL, -- 투자 상품 코드 (BTC, APPL ...)
|
||||||
name VARCHAR(100) NOT NULL,
|
model varchar(100) NULL, -- 사용한 AI 모델명 (gemini-2.5-flash-lite)
|
||||||
type VARCHAR(10) NOT NULL, -- 'CRYPTO' or 'STOCK'
|
prompt_token_count int4 NULL, -- 입력 토큰수 (AI API 응답에서 추출)
|
||||||
market VARCHAR(20) NOT NULL,
|
candidates_token_count int4 NULL, -- 출력 토큰수 (AI API 응답에서 추출)
|
||||||
is_active BOOLEAN DEFAULT true,
|
estimated_cost numeric(20, 6) NULL, -- 예상 비용 (환율반영하여 계산[원])
|
||||||
created_at TIMESTAMP DEFAULT NOW()
|
prompt_schema_version int4 NULL, -- AI 요청 프롬프트 버전 (성능 개선에 따른 버전 관리)
|
||||||
|
prompt_text text NULL, -- AI 요청에 쓰인 프롬프트 원본
|
||||||
|
response_json jsonb NULL, -- AI 응답 (JSON으로 응답 받게 설정)
|
||||||
|
requested_dt timestamp DEFAULT now() NULL, -- AI API 요청 일시
|
||||||
|
completed_dt timestamp NULL, -- AI API 응답 완료 일시
|
||||||
|
process_ms int NULL, -- AI API 처리시간 (ms단위)
|
||||||
|
error text NULL, -- 에러 메세지
|
||||||
|
CONSTRAINT ai_requests_pkey PRIMARY KEY (request_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- AI 분석결과
|
-- AI API 요청 메타 정보
|
||||||
CREATE TABLE ai_analysis (
|
CREATE TABLE public.ai_invest_metrics (
|
||||||
id SERIAL PRIMARY KEY,
|
request_id int4 NOT NULL, -- 요청 KEY (ai_requests의 키와 일치 - fk는 설정하지 않음)
|
||||||
symbol_id INTEGER REFERENCES symbols(id),
|
for_cash_entry_price numeric(20, 8) NULL, -- 현금보유자용 - 진입가
|
||||||
target_price DECIMAL(20,8),
|
for_cash_entry_price_reason text NULL, -- 현금보유자용 - 진입가를 설정한 이유
|
||||||
stop_loss_price DECIMAL(20,8),
|
for_cash_entry_price_news_article_ids INTEGER[] NULL, -- 현금보유자용 - 진입가를 설정한 이유 근거 자료(뉴스 id 리스트)
|
||||||
entry_price DECIMAL(20,8),
|
for_holding_target_price numeric(20, 8) NULL, -- 투자상품보유자용 - 목표가
|
||||||
attractiveness_score INTEGER, -- 1-100점
|
for_holding_target_price_reason text NULL, -- 투자상품보유자용 - 목표가를 설정한 이유
|
||||||
analysis_content TEXT,
|
for_holding_target_price_news_article_ids INTEGER[] NULL, -- 투자상품보유자용 - 목표가를 설정한 이유 근거 자료(뉴스 id 리스트)
|
||||||
related_news JSON,
|
for_holding_stop_loss numeric(20, 8) NULL, -- 투자상품보유자용 - 손절가
|
||||||
analysis_date TIMESTAMP DEFAULT NOW()
|
for_holding_stop_loss_reason text NULL, -- 투자상품보유자용 - 손절가를 설정한 이유
|
||||||
|
for_holding_stop_loss_news_article_ids INTEGER[] NULL, -- 투자상품보유자용 - 손절가를 설정한 이유 근거 자료(뉴스 id 리스트)
|
||||||
|
invest_score INTEGER NULL, -- 투자상품 매력도 점수 (0~100점)
|
||||||
|
CONSTRAINT ai_invest_metrics_pkey PRIMARY KEY (request_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 캔들 데이터
|
-- ai 분석 요청 플래그 (마지막 요청후 3시간 경과, 목표가/손절가 도달시)
|
||||||
CREATE TABLE invest_candle_data (
|
CREATE TABLE public.ai_request_flag (
|
||||||
id SERIAL PRIMARY KEY,
|
flag_seq serial4 NOT NULL, -- 플래그 번호
|
||||||
symbol_id INTEGER REFERENCES symbols(id),
|
invest_code varchar(10) NULL, -- 투자 상품 코드 (BTC, APPL ...)
|
||||||
open_price DECIMAL(20,8),
|
request_flag bool DEFAULT true NULL, -- AI 분석 요청 플래그 (True: AI 요청 수행해야함 / False: AI 요청 완료)
|
||||||
high_price DECIMAL(20,8),
|
flag_reason text NULL, -- AI 플래그가 발생한 이유
|
||||||
low_price DECIMAL(20,8),
|
created_dt timestamp DEFAULT now() NULL, -- 생성 일시
|
||||||
close_price DECIMAL(20,8),
|
updated_dt timestamp DEFAULT now() NULL, -- 수정 일시
|
||||||
volume DECIMAL(20,8),
|
CONSTRAINT ai_request_flag_pkey PRIMARY KEY (flag_seq)
|
||||||
candle_time TIMESTAMP,
|
|
||||||
created_at TIMESTAMP DEFAULT NOW()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 뉴스 정보
|
-- ai 프롬프트 버전 관리
|
||||||
CREATE TABLE news_info (
|
CREATE TABLE public.ai_prompt_version (
|
||||||
id SERIAL PRIMARY KEY,
|
version_seq serial4 NOT NULL, -- 버전 번호
|
||||||
symbol_id INTEGER REFERENCES symbols(id),
|
prompt text NOT NULL, -- 프롬프트 원문
|
||||||
title VARCHAR(500),
|
create_dt timestamp DEFAULT now() NULL, -- 생성 일시
|
||||||
content TEXT,
|
update_dt timestamp DEFAULT now() NULL, -- 수정 일시
|
||||||
source VARCHAR(100),
|
CONSTRAINT ai_prompt_version_pkey PRIMARY KEY (version_seq)
|
||||||
published_at TIMESTAMP,
|
|
||||||
url VARCHAR(1000),
|
|
||||||
created_at TIMESTAMP DEFAULT NOW()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 투자상품 코드 관리
|
||||||
|
CREATE TABLE public.invest_product_code (
|
||||||
|
invest_code varchar(10) NOT NULL, -- 투자 상품 코드 (BTC, APPL ...)
|
||||||
|
code_desc text NOT NULL, -- 투자 상품 코드 설명
|
||||||
|
use_yn char(1) DEFAULT 'Y' NOT NULL, -- 사용 여부부
|
||||||
|
CONSTRAINT invest_product_code_pkey PRIMARY KEY (invest_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 뉴스 데이터
|
||||||
|
CREATE TABLE public.news_articles (
|
||||||
|
news_id bigserial NOT NULL,
|
||||||
|
invest_code varchar(200) NOT NULL, -- 투자 상품 코드 (BTC, APPL ...)
|
||||||
|
"source" varchar(200) NULL, -- 뉴스 출처
|
||||||
|
author varchar(200) NULL, -- 기사 작성자
|
||||||
|
published_dt timestamp NOT NULL, -- 발생 시각
|
||||||
|
url text NULL, -- 기사 URL
|
||||||
|
title text NULL, -- 기사 제목
|
||||||
|
summary text NULL, -- 기사 요약
|
||||||
|
CONSTRAINT news_articles_pkey PRIMARY KEY (news_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 투자 상품 캔들 데이터
|
||||||
|
CREATE TABLE public.invest_candles (
|
||||||
|
invest_code varchar(10) NOT NULL, -- 투자 상품 코드 (BTC, APPL ...)
|
||||||
|
"interval" varchar(10) NOT NULL, -- 시간 기준 (MO=월, WE=주, DA=일, HO=시간, MI=분)
|
||||||
|
target_dt timestamp NOT NULL, -- 타임스탬프
|
||||||
|
"open" numeric(20, 8) NOT NULL, -- 시가
|
||||||
|
high numeric(20, 8) NOT NULL, -- 고가
|
||||||
|
low numeric(20, 8) NOT NULL, -- 저가
|
||||||
|
"close" numeric(20, 8) NOT NULL, -- 종가
|
||||||
|
volume numeric(30, 10) NULL, -- 거래량
|
||||||
|
quote_volume numeric(30, 2) NULL, -- 거래대금
|
||||||
|
"source" varchar(10) NULL, -- 데이터 출처
|
||||||
|
received_dt timestamp DEFAULT now() NULL, -- 수신 시각
|
||||||
|
CONSTRAINT market_candles_pkey PRIMARY KEY (invest_code, "interval", target_dt)
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_invest_candles_invest_code_interval_target_dt_desc ON public.market_candles USING btree (invest_code, "interval", target_dt DESC);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. 클라우드 아키텍처 (AWS)
|
## 4. 클라우드 아키텍처 (AWS)
|
||||||
|
|
||||||
### 4.1 AWS 서비스 구성
|
### 4.1 AWS 서비스 구성
|
||||||
- **S3**: 정적 웹사이트 호스팅 + AI 분석 결과 저장
|
- **Lambda**: React SSR + API 처리
|
||||||
- **CloudFront**: CDN (전세계 캐시)
|
- **S3**: 정적 에셋 호스팅 (JS/CSS/Images) + AI 분석 결과 저장
|
||||||
- **API Gateway**: API 엔드포인트 관리
|
- **CloudFront**: CDN (Lambda Origin + S3 정적 에셋)
|
||||||
- **Lambda**: 서버리스 API 처리
|
- **API Gateway**: Lambda 함수 라우팅
|
||||||
- **IAM**: 권한 관리
|
- **IAM**: 권한 관리
|
||||||
|
|
||||||
### 4.2 S3 버킷 구조
|
### 4.2 배포 아키텍처 구조
|
||||||
|
|
||||||
|
#### 4.2.1 CloudFront 배포 구조
|
||||||
|
```
|
||||||
|
CloudFront Distribution:
|
||||||
|
├── /* (Default) # Lambda SSR Origin (React HTML)
|
||||||
|
├── /assets/* # S3 Origin (JS, CSS, Images)
|
||||||
|
├── /api/* # API Gateway Origin
|
||||||
|
└── /ws/* # WebSocket API Origin
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2.2 S3 버킷 구조
|
||||||
```
|
```
|
||||||
ai-invest-bucket/
|
ai-invest-bucket/
|
||||||
├── web-assets/ # React 빌드 파일
|
├── static-assets/ # Vite 빌드된 정적 에셋
|
||||||
│ ├── index.html
|
│ ├── assets/
|
||||||
│ ├── static/
|
│ │ ├── app-[hash].js
|
||||||
│ └── assets/
|
│ │ ├── app-[hash].css
|
||||||
|
│ │ └── images/
|
||||||
|
│ └── favicon.ico
|
||||||
└── data/ # AI 분석 결과
|
└── data/ # AI 분석 결과
|
||||||
├── main/
|
├── main/
|
||||||
│ └── latest.json # 메인 페이지 데이터
|
│ └── latest.json # 메인 페이지 데이터
|
||||||
@ -259,8 +324,20 @@ WebSocket ───────────────────────
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 5.2 사용자 요청 플로우
|
### 5.2 사용자 요청 플로우
|
||||||
|
|
||||||
|
#### 5.2.1 페이지 요청 플로우
|
||||||
```
|
```
|
||||||
사용자 → CloudFront → S3 (React App) → API Gateway → Lambda → S3 Data → 응답
|
사용자 → CloudFront → Lambda SSR → S3 Data → 응답 (HTML + 초기 데이터)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5.2.2 정적 에셋 요청 플로우
|
||||||
|
```
|
||||||
|
사용자 → CloudFront → S3 (JS/CSS/Images) → 캐시된 응답
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5.2.3 API 요청 플로우
|
||||||
|
```
|
||||||
|
사용자 → CloudFront → API Gateway → Lambda → S3 Data → 응답 (JSON)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.3 AI 분석 플로우
|
### 5.3 AI 분석 플로우
|
||||||
@ -272,14 +349,21 @@ WebSocket ───────────────────────
|
|||||||
|
|
||||||
### 6.1 Frontend 최적화
|
### 6.1 Frontend 최적화
|
||||||
- **번들 최적화**: Code Splitting, Tree Shaking
|
- **번들 최적화**: Code Splitting, Tree Shaking
|
||||||
|
- **SSR 최적화**: Lambda에서 초기 렌더링으로 FCP 개선
|
||||||
|
- **정적 에셋 분리**: S3 + CloudFront로 JS/CSS 빠른 로딩
|
||||||
- **이미지 최적화**: WebP 포맷, Lazy Loading
|
- **이미지 최적화**: WebP 포맷, Lazy Loading
|
||||||
- **캐싱**: Service Worker, Browser Cache
|
- **캐싱 전략**:
|
||||||
|
- HTML: Lambda에서 동적 생성 (캐싱 제외)
|
||||||
|
- 정적 에셋: S3 + CloudFront 장기 캐싱
|
||||||
- **WebSocket**: 실시간 데이터만 필요시 연결
|
- **WebSocket**: 실시간 데이터만 필요시 연결
|
||||||
|
|
||||||
### 6.2 Backend 최적화
|
### 6.2 Backend 최적화
|
||||||
- **Lambda Cold Start**: Provisioned Concurrency 설정
|
- **Lambda Cold Start**:
|
||||||
|
- SSR Lambda: Provisioned Concurrency 설정 (사용자 체감 중요)
|
||||||
|
- API Lambda: 온디맨드 (비용 효율성)
|
||||||
- **데이터베이스**: 인덱싱, Connection Pooling
|
- **데이터베이스**: 인덱싱, Connection Pooling
|
||||||
- **S3**: CloudFront 캐시, Gzip 압축
|
- **S3**: CloudFront 캐시, Gzip 압축
|
||||||
|
- **Lambda 패키징**: webpack/rollup으로 번들 크기 최소화
|
||||||
|
|
||||||
### 6.3 비용 최적화
|
### 6.3 비용 최적화
|
||||||
- **Lambda**: 메모리 최적화, 실행시간 단축
|
- **Lambda**: 메모리 최적화, 실행시간 단축
|
||||||
@ -318,9 +402,12 @@ Local Development → Git Repository → GitHub Actions → AWS Deployment
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 9.2 CI/CD 파이프라인
|
### 9.2 CI/CD 파이프라인
|
||||||
- **Frontend**: Vite Build → S3 Upload → CloudFront Invalidation
|
- **Frontend SSR**:
|
||||||
- **Backend**: Lambda Package → AWS SAM Deploy
|
- Vite Build → Lambda 패키징 → SSR Lambda 배포
|
||||||
|
- 정적 에셋 → S3 업로드 → CloudFront Invalidation
|
||||||
|
- **API Backend**: Lambda Package → AWS SAM Deploy
|
||||||
- **Database**: Migration Scripts 자동 실행
|
- **Database**: Migration Scripts 자동 실행
|
||||||
|
- **통합 배포**: CloudFront 배포 설정 업데이트
|
||||||
|
|
||||||
### 9.3 환경 분리
|
### 9.3 환경 분리
|
||||||
- **Development**: 로컬 환경
|
- **Development**: 로컬 환경
|
||||||
|
Loading…
Reference in New Issue
Block a user