53 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
What If Invest (만약투자) is a full-stack investment simulation application that calculates hypothetical returns for cryptocurrencies and stocks using dollar-cost averaging strategies. The project consists of a React frontend, Python backend data collection services, PostgreSQL database, and AWS Lambda secure API proxy.
Critical Architecture Change (2025-10): The system migrated from KRW-only to USD-based multi-currency architecture. All investment candle data is now stored in USD with support for 7 currency conversions (KRW, JPY, CNY, EUR, BRL, VND, IDR). Cryptocurrency tickers changed from KRW-BTC
format to BTC-USD
format.
Development Commands
Frontend (React + TypeScript + Vite)
Navigate to if_invest/
directory:
- Start development server:
npm run dev
- Build for production:
npm run build
(runs TypeScript compilation then Vite build) - Lint code:
npm run lint
- Preview production build:
npm run preview
- Deploy to AWS:
npm run deploy
(runs deploy.bat - Windows batch script for complete deployment) - Deploy to S3:
npm run deploy:s3
(requires AWS CLI configured) - CloudFront invalidation:
npm run deploy:invalidate
Test Commands
- No formal test framework configured - manual testing through development server
- Type checking:
tsc -b
(TypeScript compilation check) - Production build test:
npm run preview
afternpm run build
Backend (Python Data Collection)
Navigate to 백엔드/
directory:
PostgreSQL Version (Current Production)
- Collect exchange rate data:
python collect_exchange_rate.py
(daily incremental) orpython collect_exchange_rate_full_history.py
(full history rebuild) - Collect stock daily data:
python collect_stock_candle_1d.py
(daily incremental) orpython collect_stock_candle_full_history.py
(full history rebuild) - Collect crypto daily data:
python collect_coin_candle_1d.py
(daily incremental) orpython collect_coin_candle_full_history.py
(full history rebuild) - Check collection status:
python AI가_수행하는_테스트_코드/check_collection_status.py
(verify data completeness) - Database connection: Uses
db_conn.py
with PostgreSQL - Install dependencies:
pip install pyupbit pandas psycopg2-binary python-dateutil yfinance
Important: Full history collection scripts use 6-month chunking for crypto data and period='max'
for stocks/exchange rates. These scripts convert all data to USD during collection.
Static Data Generation (Cost Optimization)
- Update all static data:
python update_static_data.py
(orchestrates all static data updates) - Investment product JSON:
python update_invest_product_json.py
(generates historical price data JSON files)- Dual output strategy:
- Copies
invest_product_list.json
andexchange_rates.json
topublic/api/
(for frontend bundling) - Uploads all 99 JSON files to S3
/api
directory (including 97 price histories)
- Copies
- File protection: Price history JSONs in S3 are excluded from frontend deployment deletion
- Dual output strategy:
S&P 500 Heatmap Data Generation (2025-10)
- Daily update (21 days):
python generate_sp500_heatmap_json.py
(automatically called byupdate_static_data.py
) - Full 3-year rebuild:
python generate_all_sp500_heatmap.py
(one-time or manual refresh) - Specific month:
python generate_sp500_heatmap_json.py --year 2025 --month 10
- Custom days:
python generate_sp500_heatmap_json.py --days 90
- Output: S3
api/sp500/YYYY/MM/heatmap_YYYYMMDD.json
(753 files, ~96KB each) - JSON Structure:
{ "date": "2025-10-03", "metadata": { "totalMarketCap": 59538.07, "totalStocks": 503, "sectors": 11 }, "data": { "NVDA": { "weight": 7.6724, "price": 187.62, "marketCap": 4567.98, "sector": "Information Technology", "sectorCode": "IT", "industry": "Semiconductors" } } }
- GICS Classification (2025-10-07): Uses official GICS standard from Wikipedia
- 11 GICS Sectors: Information Technology, Health Care, Financials, Consumer Discretionary, Industrials, Consumer Staples, Communication Services, Energy, Utilities, Real Estate, Materials
- 163 GICS Sub-Industries: Used as
industry
field (e.g., "Semiconductors", "Biotechnology") - Sector Codes: IT, HC, FN, CD, IN, CS, CP, EN, UT, RE, MT
- Data Source:
python update_gics_from_wikipedia.py
fetches classifications from Wikipedia S&P 500 list - 503 Stocks: All S&P 500 stocks classified with GICS Sector + GICS Sub-Industry
Lambda Secure API (AWS)
Navigate to lambda/
directory:
- Deploy Lambda function:
python deploy.py
(requires AWS CLI and proper IAM permissions) - Check permissions:
python check_permissions.py
(validates AWS permissions) - Manual deployment: Follow
AWS_SETUP_GUIDE.md
andDEPLOYMENT_CHECKLIST.md
- API Gateway URL:
https://c7zf9o2g6e.execute-api.ap-northeast-2.amazonaws.com/prod/api
Production Scheduling (Crontab)
Current Production Path: /home/ec2-user/eld/if_invest/
# Environment: Amazon Linux 2 / EC2 instance
# 1단계: 환율 데이터 수집 (가장 먼저 - 다른 수집에 필요)
2 6 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 collect_exchange_rate.py >> /var/log/if_invest/collect_exchange_rate.log 2>&1
# 2단계: 시장 데이터 수집 (환율 이후)
10 6 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 collect_coin_candle_1d.py >> /var/log/if_invest/collect_coin_1d.log 2>&1
15 6 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 collect_stock_candle_1d.py >> /var/log/if_invest/collect_stock_1d.log 2>&1
# 3단계: S&P 500 시가총액 수집 (주식 데이터 이후)
45 6 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 collect_sp500_market_cap_daily.py >> /var/log/if_invest/collect_sp500_market_cap.log 2>&1
# 4단계: S3 JSON 업데이트 (모든 데이터 수집 완료 후)
15 7 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 update_static_data.py >> /var/log/if_invest/update_static_data.log 2>&1
# 헬스체크 (선택사항)
0 1 * * * cd /home/ec2-user/eld/if_invest && /usr/bin/python3 AI가_수행하는_테스트_코드/check_collection_status.py >> /var/log/if_invest/health_check.log 2>&1
Crontab Best Practices:
- Always use
cd
before running scripts to ensure correct working directory - Use
>> /var/log/if_invest/*.log 2>&1
to capture both stdout and stderr - Maintain execution order: exchange rates → crypto/stocks → market cap → S3 upload
- Allow sufficient time gaps (30 minutes) between collection and upload
- Create log directory:
sudo mkdir -p /var/log/if_invest && sudo chown ec2-user:ec2-user /var/log/if_invest
- Korean Time (UTC+9): Cron times shown as UTC (e.g., 6:02 UTC = 15:02 KST)
Project Architecture
This is a multi-component application with the following structure:
Frontend Architecture (if_invest/
)
- Framework: React 19 with TypeScript and Vite 7.1.6
- Routing: React Router DOM 7.9.3 for multi-page navigation (main dashboard
/
, S&P 500 page/sp500
, legal pages) - UI Design: Dashboard layout optimized for FHD (1920x1080) screens with glassmorphism effects
- State Management: React built-in state with custom hooks (
useInvestmentCalculation
,useTheme
,useLanguageDetection
,useAdFrequency
) - API Integration Strategy (Critical - Cost Optimized):
- Bundled in Build: Investment product list (
invest_product_list.json
) and exchange rates (exchange_rates.json
) - loaded from/api
directory - Lambda API: Individual product price histories fetched on-demand during simulation only
- Cost Savings: 90%+ reduction in API calls by bundling frequently-accessed metadata
- Bundled in Build: Investment product list (
- Base Currency: USD for data storage, KRW for user display (multi-currency conversion via exchange rates)
- Investment Simulation: Client-side calculation using
investmentSimulator.ts
- Product Name Display: Korean/English hybrid strategy using
utils/productNameUtils.ts
(Korean users see Korean names, all other languages see English names) - Internationalization: 10 languages with IP-based auto-detection (43+ country mappings)
- Languages: Korean, English, Japanese, Simplified Chinese, Spanish, Portuguese, French, German, Vietnamese, Indonesian
- Date localization with
date-fns
locale support for each language - Language selector dropdown in header with native names and flag emojis
- Analytics: Google Analytics 4 for user behavior tracking and geographic insights
- Event tracking: asset selection, investment simulation, results view, language/theme changes
- User properties: language preference, currency (KRW), theme selection
- Geographic analytics: continental/country-level statistics
- Monetization: Google AdSense integration with production ads (2025-10-05)
- Production Configuration: Real AdSense account active (
ca-pub-6461991944599918
) - Ad Placement: Vertical ads (left/right), horizontal ads (top/bottom), video ad modal (3-second countdown)
- Ad Format: Responsive ads using
data-ad-format="auto"
anddata-full-width-responsive="true"
- Component:
GoogleAdSense.tsx
replaced all placeholderAdSpace.tsx
components - Environment Variables:
.env
contains production Client ID and Slot ID (1439731527)
- Production Configuration: Real AdSense account active (
- SEO Optimization (2025-10-05):
- Google Search Console: Verified ownership and sitemap submitted
- Sitemap:
public/sitemap.xml
with 4 pages and multilingual alternatives (10 languages) - Robots.txt:
public/robots.txt
allows all crawlers and references sitemap - Meta Tags: Comprehensive English SEO meta tags (Open Graph, Twitter Cards, keywords)
- Noscript Content: 2000+ words of crawlable content for search engines (features, supported assets, DCA explanation)
- Global Strategy: English meta tags for worldwide reach despite 10-language support
- Legal Compliance: Privacy Policy, Terms of Service, and Disclaimer pages (fully translated)
- Environment Variables:
.env
contains GA4 measurement ID (VITE_GA4_MEASUREMENT_ID
) and AdSense configuration - Key Dependencies:
recharts
(3.2.1) for data visualizationi18next
(25.5.2) for internationalization with 10 language filesreact-router-dom
(7.9.3) for routingaxios
(1.12.2) for HTTP requestsdate-fns
(4.1.0) with 10 locale imports for date localization
Lambda Secure API Architecture (lambda/
)
- Purpose: Secure proxy layer between frontend and S3 data
- Runtime: Python 3.9 on AWS Lambda
- Security Features: Origin validation, rate limiting, bot detection
- API Gateway: REST API with CORS enabled
- S3 Integration: Proxies requests to static JSON files in S3 bucket
- Environment-specific: Production uses secure API, development uses local files
Backend Architecture (백엔드/
and backend_test/
)
- Language: Python 3.x
- Database: PostgreSQL (host: 3.38.180.110:8088, db: if_invest)
- Production Scripts:
백엔드/
directory for scheduled data collection (cron jobs) - Experimental Scripts:
backend_test/
directory for testing new collection strategies - Data Collection: Automated scripts for market data gathering via external APIs
- Logging: Custom logger implementation in
logger.py
with append mode and date-based file rotation- Log files:
./logs/yyyy/mm/script_name_logger_dd.log
format - Critical: FileHandler uses
mode='a'
to preserve logs across multiple daily executions
- Log files:
- Database Connection:
DBConn
class indb_conn.py
with bulk upsert capabilities
Data Flow Architecture
- Data Collection: Python scripts collect historical price data from external APIs (yfinance, pyupbit, exchangerate-api)
- Exchange Rates: 7 currencies (KRW, JPY, CNY, EUR, BRL, VND, IDR) collected as
1 USD = X target_currency
- Stocks: Yahoo Finance data in local currency → converted to USD using exchange rates
- Crypto: Upbit KRW pairs → converted to USD using KRW/USD exchange rates
- S&P 500 Market Cap: Daily collection of 503 stocks with sector/industry metadata (yfinance)
- Exchange Rates: 7 currencies (KRW, JPY, CNY, EUR, BRL, VND, IDR) collected as
- Database Storage: All data stored in PostgreSQL in USD with structured tables (invest_candles, invest_product_code, exchange_rates, stock_market_cap_history)
- Product Filtering: Investment product codes filtered by
code_type
('STOCK'/'COIN') anduse_yn
('Y') for active collection - Static JSON Generation: Scripts generate JSON files from PostgreSQL
- Bundled Files (copied to
public/api/
for frontend build):invest_product_list.json
- Product metadata (110 products)exchange_rates.json
- Multi-currency conversion data (7 currencies)
- S3-Only Files (uploaded to S3
/api
directory):{TICKER}_price_history.json
- 97 individual product price historiessp500/YYYY/MM/heatmap_YYYYMMDD.json
- 753 S&P 500 heatmap files (3 years)
- Bundled Files (copied to
- Frontend Build: Vite copies
public/api/
files todist/api/
during build - S3 Deployment Strategy (CRITICAL - 2025-10-12):
- Frontend:
aws s3 sync dist/ s3://if-invest/ --delete --exclude "api/*_price_history.json" --exclude "api/sp500/**"
- Backend: Uploads individual price history JSONs + S&P 500 heatmaps to S3 (protected from frontend deletion)
- CRITICAL:
--exclude "api/sp500/**"
flag is MANDATORY to prevent deletion of 758 S&P 500 heatmap files during frontend deployment - File Protection: Both
--exclude
flags protect backend-generated data from being wiped by frontendnpm run deploy
- Frontend:
- Secure API Proxy: AWS Lambda + API Gateway provides secure access to individual product price data from S3
- Client-Side Simulation: Frontend loads bundled product list and exchange rates, fetches detailed price data via Lambda API only when simulation requested
- Currency Display Conversion: Frontend converts USD data to KRW for user display using exchange rates
Multi-Environment Architecture
- Development: Frontend uses local JSON files in
public/api/
directory - Production: Frontend uses secure API Gateway endpoint for S3 data access
- Security Layer: Lambda function validates origins, implements rate limiting, and prevents direct S3 access
- Cost Optimization: Static JSON files reduce database queries by 90-95%
Key Backend Data Collection
Market Data Sources
- Exchange Rates: 7 currency pairs from Yahoo Finance (USDKRW=X, USDJPY=X, USDCNY=X, EURUSD=X, USDBRL=X, USDVND=X, USDIDR=X)
- EUR special handling: EURUSD data inverted to get USD/EUR (1 USD = X EUR)
- Historical data: JPY oldest (1996), KRW from 2003
- Stock Data: Daily candle data from Yahoo Finance (yfinance)
- Supports: US (USD), Korea (.KS, KRW), Japan (.T, JPY), Spain (.MC, EUR), Brazil (.SA, BRL), France (.PA, EUR), Germany (.DE, EUR)
- Not supported: Hong Kong (.HK, HKD), Vietnam (.VN, VND), Indonesia (.JK, IDR) - marked as
use_yn='N'
- Crypto Data: Daily candle data from Upbit API (pyupbit) - KRW pairs converted to USD
- Ticker format:
BTC-USD
,ETH-USD
(stored in DB) vsKRW-BTC
,KRW-ETH
(Upbit API request) - Ticker mapping defined in
COIN_TICKER_MAP
in collection scripts:{'BTC-USD': 'KRW-BTC', 'ETH-USD': 'KRW-ETH', ...}
- Historical data: From 2017-09-01 (Upbit service start)
- Missing coins: LTC-USD, MATIC-USD, ICP-USD (no Upbit data available)
- Ticker format:
- Data Coverage: ~80 stocks (10 Korean + 40 US + international) and 20 cryptocurrencies (17 available on Upbit)
Database Connection Patterns
PostgreSQL (Current Production)
- Connection Class:
DBConn
indb_conn.py
- Host: 3.38.180.110:8088, Database: if_invest
- Credentials: eldsoft/eld240510 (hardcoded, should be moved to environment variables)
- Driver: psycopg2
- Key Features:
- Bulk upsert operations via
bulk_upsert()
with conflict resolution - Connection pooling and automatic reconnection
- Product code filtering by
code_type
anduse_yn
- Comprehensive error handling and transaction management
- Bulk upsert operations via
- Logging: All database operations logged via custom
logger.py
Critical Implementation Notes
Frontend Development
- TypeScript: Use
import type { TypeName }
for type-only imports (required byverbatimModuleSyntax
)- Import
Locale
type fromdate-fns/locale
when using locale objects
- Import
- Build Tool: Vite 7.1.6 with React 19 support and Hot Module Replacement
- Production Logging Policy (2025-10):
- ONLY use
console.error()
for critical error debugging in production - NEVER use
console.log()
orconsole.warn()
in production code - All simulation logs, currency conversion logs, and language detection logs have been removed
- Exception: console.error remains for API failures, data loading errors, and critical exceptions
- ONLY use
- Routing Architecture: Multi-page SPA with:
- Main dashboard:
/
(investment simulation) - S&P 500 page:
/sp500
(sector visualization - in development) - Legal pages:
/privacy-policy
,/terms-of-service
,/disclaimer
- Header navigation includes buttons to switch between simulation and S&P 500 pages
- Main dashboard:
- Internationalization: 10 languages with IP-based auto-detection via
ipapi.co
geolocation.ts
: Maps 43+ country codes to appropriate languagesuseLanguageDetection.ts
: Handles automatic detection and manual language switchingi18n/locales/
: 10 JSON files (ko, en, ja, zh-CN, es, pt, fr, de, vi, id) with complete translations including legal documents- Language selector in header uses dropdown with native names and flag emojis
- Translation placeholders: Use i18next interpolation syntax
{{variable}}
for dynamic values - Example:
"dayOfMonth": "투자일 (매월 {{day}}일)"
requirest('investmentSettings.dayOfMonth', { day: dayOfMonth })
- Date Localization: All dates in charts and tables localized using
date-fns
with language-specific formatsChartArea.tsx
andInvestmentTableModal.tsx
import all 10 locales fromdate-fns/locale
- Format patterns vary by language (e.g., "yyyy년 MM월 dd일" for Korean, "MMM dd, yyyy" for English)
- Analytics Integration: Google Analytics 4 tracking via
analytics.ts
service- Track events:
trackInvestmentSimulation
,trackAssetTypeSelection
,trackLanguageChange
,trackThemeChange
, etc. - Set user properties:
setUserProperties({ language, currency, theme })
- Events fire automatically on user interactions (DO NOT add redundant tracking)
- Track events:
- Purchase Logic: Crypto allows fractional quantities, stocks require whole shares
- Chart Tooltips: Enhanced with 5-piece information display (total investment, evaluation, daily purchase, total holdings, unit price)
- API Integration: All external data fetching handled by backend to avoid CORS
- Layout: FHD-optimized with responsive breakpoints at 1200px and 768px
- Theme System: Comprehensive light/dark mode using CSS custom properties
- CRITICAL: Dark mode design is finalized and should NOT be modified
- Light mode may need improvements for better visibility and tone/manner consistency
- Use
[data-theme="dark"]
selector for dark mode specific styles - Use
body:not([data-theme="dark"])
selector for light mode only styles
- Chart Library: Recharts for investment visualization and data display
- Currency Symbol Display: Y-axis legend must show currency-appropriate symbols based on selected currency
- Currency symbols: USD (
), KRW (원), JPY (¥), CNY (¥), EUR (€), BRL (R
), VND (₫), IDR (Rp) - Chart legend formatter in
ChartArea.tsx
line 338-353 handles currency symbol mapping
- Ad Integration: Google AdSense with environment-based configuration (test/production keys)
- Ad Frequency Logic (2025-10): First 3 simulations free, then video ad every 3rd simulation
- Implemented in
useAdFrequency.ts
hook with localStorage tracking
- Currency Input System (2025-10):
- 7 currency support for investment amount input: USD, KRW, JPY, CNY, EUR, BRL, VND, IDR
- Dropdown selector in investment settings replaces previous button-based approach
- Exchange rate conversion: input currency → USD (for API) → display currency (for chart)
- Quick adjustment buttons: +1, +10, +100, +1000, ×2, ×10, ÷2, ÷10 for amount input
- Mobile-optimized with
inputMode="numeric"
for numeric keyboard - Investment currency selection automatically sets chart display currency
- Legal Pages: Fully internationalized legal documents with consistent styling across all 10 languages
- Bundle Size: Warning expected due to 10 language files + date-fns locales (acceptable, optimize with dynamic imports only if performance issues arise)
- Product Name Display Strategy: Korean/English hybrid approach (implemented 2025-10)
- Use
getProductName(product, i18n.language)
fromutils/productNameUtils.ts
- Korean users (
i18n.language === 'ko'
): Displaycode_desc_kr
field - All other language users: Display
code_desc_en
field - Ticker codes always displayed alongside names
- Benefits: No DB changes needed, avoids 900 translations (90 products × 10 languages), maintains accuracy with official English names
- Components using this:
InvestmentSidebar.tsx
,CompactAssetSelector.tsx
- Use
- S&P 500 Sector Visualization Page (
/sp500
- 2025-10):- Layout System: Fixed coordinate-based sector box positioning (not treemap algorithm)
- Canvas Size: 1880px × 1020px absolute pixel coordinates
- Sector Boxes: 11 manually positioned rectangular boxes for GICS sectors
- Coordinate System: Each sector defined by (x1, y1, x2, y2) pixel coordinates
- Responsive Sizing: Small sectors (8-11) use reduced font sizes and icon-only buttons
- CRITICAL - GICS Sector Naming (2025-10-11):
- MUST USE OFFICIAL GICS NAMES from database exactly as stored
- Sector names in code MUST match
invest_product_code.sector
column values - Correct GICS Sector Names (11 official sectors):
"Information Technology"
(NOT "TECHNOLOGY")"Financials"
(NOT "FINANCIAL")"Consumer Discretionary"
(NOT "CONSUMER CYCLICAL")"Health Care"
(NOT "HEALTHCARE" - note the space)"Industrials"
(correct)"Consumer Staples"
(NOT "CONSUMER DEFENSIVE")"Communication Services"
(correct)"Energy"
(correct)"Utilities"
(correct)"Real Estate"
(correct - note the space)"Materials"
(NOT "BASIC MATERIALS")
- Where to Update:
SECTOR_BOXES
array (SP500Page.tsx lines 40-59)- Technology sector conditional:
box.name === "Information Technology"
(line 948) - Non-technology conditional:
box.name !== "Information Technology"
(line 1582) - Modal dropdown options (lines 814-824)
- CSS data-sector attributes (SP500Page.css lines 444-508)
- Impact: Incorrect names cause data filtering failure (0 stocks displayed)
- Detail Button: Text "상세보기" for large sectors, magnifying glass icon for small sectors
- Content Areas: Each sector has header (title + detail button) and content area for stock treemap display
- Design Pattern: Absolute positioning with inline styles for exact pixel placement
- CRITICAL: Use coordinate-based manual layout, NOT algorithmic treemap layouts (Recharts, D3, squarify)
- Data Source: Lambda API endpoint
/api/sp500/heatmap/{date}
returns GICS-classified data - Database as Source of Truth:
- CRITICAL: Always use DB column values exactly as stored (
invest_product_code.sector
andinvest_product_code.industry
) - DB has 503 S&P 500 stocks with
is_sp500='Y'
flag - All 11 GICS sectors and 163 sub-industries are correctly classified in database
- Frontend Industry mapping MUST match DB values precisely (case-sensitive, hyphen-sensitive)
- Example correct mappings:
- "SOFTWARE-INFRASTRUCTURE" (16 stocks: MSFT, ORCL, PLTR, PANW, CRWD, SNPS, FTNT, XYZ, etc.)
- "SOFTWARE-APPLICATION" (17 stocks: CRM, ADBE, INTU, NOW, etc.)
- "SEMICONDUCTORS" (13 stocks: NVDA, AMD, INTC, etc.)
- "INFORMATION TECHNOLOGY SERVICES" (11 stocks: ACNX, IBM, etc.)
- "SEMICONDUCTOR EQUIPMENT & MATERIALS" (4 stocks: AMAT, KLAC, LRCX, TER)
- "ELECTRONIC COMPONENTS" (4 stocks: APH, GLW, JBL, TEL)
- "CONSUMER ELECTRONICS" (1 stock: AAPL only)
- CRITICAL: Always use DB column values exactly as stored (
- Technology Sector Implementation (Complete):
- 10 Industry subdivisions with fixed coordinate layout
- SOFTWARE-INFRASTRUCTURE: Manual layout for 8 major stocks (MSFT 60%, ORCL, PLTR, PANW, CRWD, SNPS, FTNT, XYZ, FFIV)
- ELECTRONIC COMPONENTS: 4 stocks (APH top 50%, GLW/TEL/magnifying glass 3:3:1 bottom)
- SCIENTIFIC & TECHNICAL INSTRUMENTS: 5 stocks (KEYS, TDY, magnifying glass 1:1:1 horizontal)
- SOLAR: 1 stock (FSLR full area)
- Other industries: Squarified treemap algorithm (
calculateTreemapLayout()
) - Stock boxes colored by price change: green (>+1%), gray (0~+1%), dark red (0~-1%), red (<-1%)
- 5-stage dynamic font sizing system (see below)
- Financial Sector Implementation (Complete - 2025-10-12):
- 11 Industry subdivisions with fixed coordinate layout (800px × 377px sector)
- Layout structure:
- Left 60% (480px): BANKS-DIVERSIFIED (160px), CREDIT SERVICES (160px), INSURANCE-DIVERSIFIED + CAPITAL MARKETS (160px split 3:2)
- Right 40% (320px): 7 industries in complex grid layout
- All industries use treemap algorithm for stock positioning
- Industry boxes with 1px padding on all sides
- Headers flush left (left: "0px") with full width
- Identical styling to TECHNOLOGY sector (hover effects, tooltips, aggregation)
- 5-Stage Font Sizing System (2025-10-12):
- Stage 1 (>15000px²): Ticker 32px, percent 65% of ticker, % sign shown (MSFT, NVDA, AAPL - 2x size increase)
- Stage 2 (>8000px²): Ticker 24px, percent 65% of ticker, % sign shown (ORCL, AVGO, AMD)
- Stage 3 (>3000px²): Ticker 16px, percent 70% of ticker, % sign shown (medium boxes)
- Stage 4 (>1000px²): Ticker 9-12px, percent 75% of ticker, % sign removed (small boxes)
- Stage 5 (≤1000px²): Ticker 6-9px, percent display completely removed (very small boxes)
- Applied to all sectors consistently
- Formula:
boxArea = item.width * item.height
- Aggregated Stock Boxes (2025-10-11):
- Small stocks (< 50px minSize) aggregated into single box per industry
- Positioned at bottom-right corner:
position: absolute; right: 4px; bottom: 4px
- Market-cap weighted average:
Σ(changePercent × marketCap) / Σ(marketCap)
- Dynamic sizing: 40-60px based on filtered stock count
- Color-coded using same 7-tier gradient as regular stocks
- Display:
+N
count with tooltip showing all filtered stocks - Hover tooltip shows complete list of aggregated stocks sorted by weight
- Date Comparison System (2025-10-12):
- Two-date selector: "기준 날짜" (currentDate - most recent) vs "비교 날짜" (previousDate - second most recent)
- Auto-initialization: On page load, automatically sets most recent 2 dates from API
- Calendar UI with month navigation
- Only dates with available DB data are selectable
- Price change calculation:
(current - previous) / previous * 100
- Critical: Label mapping in DateSelector.tsx must match: currentDate="기준 날짜", previousDate="비교 날짜"
Backend Development
- Database Credentials: PostgreSQL credentials hardcoded in
db_conn.py
(should be moved to environment variables) - Error Handling: Comprehensive logging via custom logger with append mode
- Logger uses
FileHandler(mode='a')
to preserve logs from multiple daily executions - Log directory structure:
./logs/yyyy/mm/script_name_logger_dd.log
- Each script execution appends to same-day log file instead of overwriting
- Logger uses
- Data Integrity: Bulk upsert operations with conflict resolution using ON CONFLICT clause
- Pandas Data Handling: Critical to properly convert pandas Series to scalar values using
.item()
method - Exchange Rate Conversion: All non-USD data converted to USD using historical exchange rates from database
- Formula:
local_amount * (1 / usd_to_local_rate) = usd_amount
- Example:
1000 KRW * (1 / 1300) = 0.769 USD
- Formula:
- Data Collection Optimization:
- Recent 2-3 days data collection to ensure up-to-date information
- Bulk upsert operations for efficient database updates
- Static JSON generation for frontend consumption
- Full History Collection:
- Crypto: 6-month chunks with
count=200
per API call - Stocks/Exchange Rates:
period='max'
for complete history - All data converted to USD during collection
- Crypto: 6-month chunks with
- S&P 500 Market Cap Collection (2025-10):
- Daily collection: 503 stocks × 21 days with upsert
- Calculation:
hist['Close'] * shares_outstanding / 1_000_000_000
(market cap in billions) - Weight calculation: After data collection, compute
(stock_market_cap / total_sp500_market_cap) × 100
for each date - GICS Classification (2025-10-07): Sector/Industry now uses official GICS standard from Wikipedia
- Sector: GICS Sector (11 categories: Information Technology, Health Care, Financials, etc.)
- Industry: GICS Sub-Industry (163 categories: Semiconductors, Biotechnology, etc.)
- Source:
python update_gics_from_wikipedia.py
fetches and updates all 503 S&P 500 stocks
- Time Zone: All
created_at
timestamps use Korean time (UTC+9) viaCURRENT_TIMESTAMP + INTERVAL '9 hours'
Security Considerations
- PostgreSQL: Credentials hardcoded in
db_conn.py
(host: 3.38.180.110:8088, db: if_invest, user: eldsoft, password: eld240510) - API Keys: All external API calls handled server-side to prevent key exposure
- Data Validation: Proper input sanitization and type conversion for PostgreSQL compatibility
- S3 Upload: Requires AWS CLI configuration with appropriate IAM permissions for S3 access
Development Workflow
- Frontend Development: Work in
if_invest/
directory with hot reload vianpm run dev
- Backend Development: Work in
백엔드/
directory for production data collection - Testing: Use
backend_test/
directory for experimental data collection scripts - Database Operations: Use
DBConn
class indb_conn.py
for PostgreSQL operations - Static Data Generation: Run
update_static_data.py
to generate JSON files for S3 upload
Phase 2 Development (AI-Based Future Prediction)
Overview
Phase 2 focuses on transitioning from historical "what if" simulations to AI-powered future predictions, targeting beginner investors who need clear explanations and credible sources.
Core Concept: "과거 시뮬레이션" (Past Simulation) → "미래 예측" (Future Prediction)
- Phase 1: "What if you invested in the past?"
- Phase 2: "What returns can you expect if you invest now?"
AI Prediction Workflow (설계/2차/)
1. Generate AI Analysis Request Files
Navigate to 설계/2차/
directory and use the file generation script:
cd "설계/2차"
python generate_files.py <TICKER>
# Examples:
python generate_files.py TSLA # Tesla stock
python generate_files.py BTC-USD # Bitcoin
python generate_files.py 005930.KS # Samsung Electronics (Korean stock)
Generated Files (2 per ticker):
{TICKER}_candle_data_YYYYMMDD.csv
- Historical OHLCV data from PostgreSQL{TICKER}_ai_prompt.py
- Prompt template for Claude.ai analysis
2. Claude.ai Analysis Process
- Access: https://claude.ai
- Model: Claude 3.5 Sonnet with Extended Thinking
- Settings: Enable "Thinking" + "Research" features
- Input:
- Attach CSV file
- Run
python {TICKER}_ai_prompt.py
to get prompt text - Paste prompt into Claude.ai
- Output: Save JSON response as
AI응답_{TICKER}.json
3. Expected JSON Response Structure
{
"1_캔들데이터": {
"period": "3 years from last date",
"frequency": "weekly",
"total_weeks": 156,
"data": [{"week": 1, "date": "YYYY-MM-DD", "open": 0, "high": 0, "low": 0, "close": 0}]
},
"2_애널리스트_분석": {
"summary": "Analyst consensus summary",
"average_target_price": 0,
"recommendations": {"buy": 0, "hold": 0, "sell": 0},
"key_analysts": [{"firm": "...", "rating": "...", "target_price": 0, "source_url": "..."}],
"sources": [{"title": "...", "url": "...", "date": "..."}]
},
"3_최신뉴스_요약": {
"summary": "Recent news summary",
"sentiment": "긍정적/중립/부정적",
"positive_news": [{"headline": "...", "url": "...", "impact": "..."}],
"negative_news": [{"headline": "...", "url": "...", "impact": "..."}]
},
"4_캔들데이터_분석": {
"long_term_trend": {"description": "...", "cagr_5y": "...", "cagr_10y": "..."},
"volatility": {"annual_volatility": "...", "max_drawdown": "..."},
"seasonal_patterns": {"Q1": "...", "Q2": "...", "Q3": "...", "Q4": "..."}
}
}
Key Phase 2 Requirements
AI Analysis Must Include:
- 3-year weekly predictions (156 weeks total) - for chart visualization
- Evidence-based reasoning - all predictions must cite news/analyst reports with URLs
- Multi-source validation - latest news, analyst ratings, financial metrics, historical patterns
- Conservative approach - avoid exaggerated predictions, emphasize risks
Target User: Beginner investors who cannot interpret:
- Complex financial charts
- News headlines
- Analyst reports
- Need clear explanations with credible sources
Phase 2 Design Documents
Located in 설계/2차/
:
00_2차_개발_방향성_논의.md
- Overall Phase 2 direction and options01_AI_기반_투자_예측_서비스_설계.md
- Detailed AI prediction service designgenerate_files.py
- Automated CSV + prompt generation script
Critical Differences from Phase 1
Aspect | Phase 1 (Historical) | Phase 2 (Predictive) |
---|---|---|
Question | "What if I invested in the past?" | "What returns can I expect now?" |
Data Source | Historical candle data only | Historical data + AI analysis of news/analysts |
Output | Past performance chart | 3-year future prediction chart with reasoning |
Credibility | Factual historical data | Requires sources/evidence for all predictions |
Chart Type | Actual historical returns | Predicted weekly returns (156 weeks) |
Common UI/UX Issues and Solutions
Currency Display
- Issue: Chart Y-axis showing wrong currency symbol after currency change
- Solution: Ensure currency symbol mapper in
ChartArea.tsx
YAxis tickFormatter usesselectedCurrency
state - Implementation: Create currency symbol Record mapping in tickFormatter function
Translation Issues
- Issue: Hardcoded Korean text not internationalized (e.g., "총 12건의 투자 기록")
- Solution: Add translation keys to all 10 language files with proper interpolation
- Pattern:
- Add key to
ko.json
:"recordCount": "총 {{count}}건의 투자 기록"
- Use in component:
t('table.recordCount', { count: records.length })
- Replicate to all language files (ja, zh-CN, es, pt, fr, de, vi, id, en)
- Add key to
Theme-Specific Styling
- Issue: Style changes affecting both light and dark mode when only one should change
- Solution: Use theme-specific CSS selectors
- Dark mode only:
[data-theme="dark"] .class-name { ... }
- Light mode only:
body:not([data-theme="dark"]) .class-name { ... }
- WARNING: NEVER modify dark mode styles without explicit user request
Light Mode Design Improvements (2025-10)
- Background Hierarchy:
--bg-primary: #F5F5F7
(페이지 배경) vs--bg-card: #FFFFFF
(카드 배경) - Enhanced Shadows: Use
rgba(0, 0, 0, 0.06~0.12)
for better depth perception - Border Colors:
--border-primary: #E5E5E5
for subtle section separation - Visual Depth: Cards "float" above background with enhanced box-shadow
- Implementation: Modified CSS variables in
theme.css
(:root
section only, dark mode untouched)
Mobile Responsive Design (Critical - 2025-10-08)
CRITICAL: The chart will NOT render on mobile (≤1024px) if these CSS properties are not correctly set:
Root Cause of Chart Rendering Issues
-
.content-area
and.sidebar-area
must havemin-width: 0
andmin-height: 0
in base styles- Default
min-width: 700px
ormin-height: 600px
breaks flex layout on mobile - These prevent the mobile flex-direction: column from working properly
- Default
-
.chart-area-main
must haveheight: auto
(NOTheight: 100%
)height: 100%
causes ResponsiveContainer to fail rendering when parent height is not explicit- Set to
auto
in base styles, then override with specificmin-height
values in media queries
-
.chart-container
must haveflex: none
in mobile media queries- Default
flex: 1
causes height calculation issues on mobile - Must use
!important
flag to override base styles
- Default
Required Mobile CSS Pattern (NewDesign.css)
/* Base styles - CRITICAL */
.content-area {
flex: 3;
min-width: 0; /* NOT 700px */
min-height: 0; /* NOT 600px */
display: flex;
flex-direction: column;
}
.sidebar-area {
width: 340px;
flex-shrink: 0;
min-height: 0; /* NOT 600px */
}
.chart-area-main {
display: flex;
flex-direction: column;
height: auto; /* NOT 100% */
min-height: 700px;
gap: 1.5rem;
}
.chart-container {
height: 600px;
min-height: 600px;
/* ... */
flex: 1; /* This will be overridden on mobile */
}
/* Mobile breakpoints */
@media (max-width: 1024px) {
.main-layout {
flex-direction: column; /* Stack vertically */
padding: 1rem;
gap: 1.5rem;
}
.sidebar-area {
width: 100%;
order: -1; /* Sidebar appears first */
}
.content-area {
order: 1;
min-width: 0;
min-height: 0;
width: 100%;
}
.chart-area-main {
min-height: 500px !important;
height: auto !important;
}
.chart-container {
height: 500px !important;
min-height: 500px !important;
flex: none !important; /* CRITICAL: Remove flex: 1 */
}
}
@media (max-width: 768px) {
.chart-area-main {
min-height: 450px !important;
height: auto !important;
}
.chart-container {
height: 450px !important;
min-height: 450px !important;
flex: none !important;
}
}
@media (max-width: 480px) {
.chart-area-main {
min-height: 400px !important;
height: auto !important;
}
.chart-container {
height: 400px !important;
min-height: 400px !important;
flex: none !important;
}
}
Mobile Layout Behavior
- ≥1025px: Desktop layout with sidebar on right (flex-direction: row)
- ≤1024px: Mobile layout with sidebar on top (flex-direction: column)
- Chart heights scale down: 500px (1024px), 450px (768px), 400px (480px)
Debugging Mobile Chart Issues
If chart doesn't render on mobile:
- Check
.content-area
base styles havemin-width: 0
andmin-height: 0
- Check
.chart-area-main
base style hasheight: auto
(notheight: 100%
) - Verify media queries use
!important
flags for overrides - Ensure
.chart-container
hasflex: none !important
in mobile media queries - Test in browser dev tools with responsive mode (≤1024px width)
Development Environment
Frontend Development Server
- Port: 5173 (Vite dev server via
npm run dev
) - Build Output:
dist/
directory for production deployment - Development API: Uses local JSON files in
public/api/
directory
Secure API Endpoints (Production)
- Base URL:
https://c7zf9o2g6e.execute-api.ap-northeast-2.amazonaws.com/prod/api
- Investment Product List:
GET /api/invest_product_list
- Individual Product Data:
GET /api/{ticker}
(e.g.,/api/KRW-BTC
)
Investment Simulation Logic
The frontend uses investmentSimulator.ts
for client-side calculations with the following key features:
- Automatic start date calculation based on investment period and frequency
- Asset Type Detection:
params.investCode.endsWith('-USD')
identifies crypto (allows fractional), otherwise stock (whole shares only) - Price lookup with triple fallback:
- Exact date match
- Nearest previous date
- Latest available data (new fallback for missing historical dates)
- Real-time evaluation using latest market price for profit/loss calculations
- Data Sources:
- Product list & exchange rates: Bundled in build (
/api
directory) - Individual price histories: Lambda API on-demand during simulation
- Product list & exchange rates: Bundled in build (
File Structure Highlights
if_invest/ # React frontend application
├── src/
│ ├── components/ # React components
│ │ ├── layout/ # DashboardLayout, Header, Footer (with router navigation)
│ │ ├── common/ # InvestmentSidebar, shared components
│ │ ├── results/ # ChartArea, InvestmentTableModal
│ │ ├── ads/ # AdSpace (placeholder), GoogleAdSense, VideoAdModal
│ │ ├── sp500/ # SP500Page (sector visualization)
│ │ └── legal/ # PrivacyPolicy, TermsOfService, Disclaimer (i18n enabled)
│ ├── services/ # API integration and business logic
│ │ ├── apiService.ts # Secure API communication (environment-specific)
│ │ ├── investmentSimulator.ts # Client-side calculation engine
│ │ ├── geolocation.ts # IP-based language detection with 43+ country mappings
│ │ └── analytics.ts # Google Analytics 4 event tracking
│ ├── hooks/ # Custom React hooks
│ │ ├── useInvestmentCalculation.ts # Investment calculation state
│ │ ├── useTheme.ts # Light/dark theme management
│ │ ├── useLanguageDetection.ts # IP-based language detection
│ │ ├── useAdFrequency.ts # Advertisement display frequency
│ │ └── useResponsiveAds.ts # Responsive ad layout management
│ ├── i18n/ # Internationalization setup
│ │ ├── i18n.ts # i18next configuration with 10 language resources
│ │ └── locales/ # 10 translation files (ko, en, ja, zh-CN, es, pt, fr, de, vi, id) with legal content
│ ├── utils/ # Utility functions
│ │ └── productNameUtils.ts # Korean/English hybrid product name display logic
│ ├── types/ # TypeScript interfaces
│ ├── styles/ # Modular stylesheets
│ │ ├── AdStyles.css # Advertisement layout and styling
│ │ └── LegalPages.css # Legal document styling
│ └── *.css # Core stylesheets (NewDesign.css, theme.css)
├── public/ # Static assets
│ └── api/ # Local JSON files for development
├── .env # Environment variables (GA4 measurement ID, AdSense client ID)
├── index.html # HTML with GA4 gtag.js, AdSense meta tags and scripts
├── package.json # Dependencies and scripts
├── deploy.bat # Windows deployment script
└── CLAUDE.md # Project guidance for Claude Code
백엔드/ # Production Python backend
├── collect_*.py # PostgreSQL data collection scripts
├── db_conn.py # PostgreSQL connection class
├── update_static_data.py # Orchestrates all static data updates
├── update_invest_product_json.py # Generates JSON files from PostgreSQL for S3
├── table_ddl.sql # Database schema definitions
├── test.py # Test script for data collection
├── logger.py # Logging utilities with file rotation
├── logs/ # Log files directory
└── __pycache__/ # Python bytecode cache
lambda/ # AWS Lambda secure API
├── secure_api_proxy.py # Lambda function code with security features
├── deploy.py # Automated deployment script
├── trust-policy.json # IAM role trust policy
├── config.json # AWS configuration
├── AWS_SETUP_GUIDE.md # Manual deployment guide
└── DEPLOYMENT_CHECKLIST.md # Deployment verification checklist
backend_test/ # Test/experimental backend scripts
설계/ # Design documentation
AI요청/ # AI development requests
Database Schema
PostgreSQL Tables (Current Production - USD-based Schema)
invest_candles
- Primary Key:
invest_code
,interval
,target_dt
(composite key) - Columns:
open
,high
,low
,close
,volume
,source
,received_dt
- Usage: OHLCV candle data for stocks and crypto in USD
- Example: invest_code='BTC-USD', interval='1d', target_dt='2024-01-01'
- Data Types:
varchar(20)
for invest_code (changed from varchar(10) to support longer tickers),numeric(20, 8)
for prices
invest_product_code
- Primary Key:
invest_code
- Columns:
code_desc_kr
,code_desc_en
,code_type
,base_cash
,use_yn
,desc
,is_sp500
,sector
,industry
- New Columns (2025-10 migration):
base_cash varchar(10)
: Source currency (USD, KRW, JPY, EUR, etc.)desc text
: Reason for deactivation or notesis_sp500 varchar(1)
: 'Y' for S&P 500 stocks, NULL otherwisesector varchar(50)
: GICS Sector classification (e.g., "Information Technology")industry varchar(100)
: GICS Sub-Industry classification (e.g., "Semiconductors")
- Usage: Master list of investment products (stocks and coins)
- Filtering: Scripts query by
code_type
('STOCK'/'COIN') anduse_yn
('Y') - S&P 500 Filtering: Query by
is_sp500='Y'
for S&P 500 stocks only (503 stocks) - GICS Classification (2025-10-07): Sector and industry fields updated from Wikipedia GICS data
- Example: invest_code='NVDA', code_desc_kr='엔비디아', code_desc_en='NVIDIA', code_type='STOCK', base_cash='USD', use_yn='Y', is_sp500='Y', sector='Information Technology', industry='Semiconductors'
exchange_rates
- Primary Key:
base_currency
,target_currency
,exchange_date
- Columns:
rate
,open_rate
,high_rate
,low_rate
,close_rate
,source
,received_dt
- Usage: Multi-currency exchange rate data (always base_currency='USD')
- Format:
1 USD = X target_currency
(e.g., 1 USD = 1300 KRW) - Supported Currencies: KRW, JPY, CNY, EUR, BRL, VND, IDR (7 currencies)
stock_market_cap_history (2025-10)
- Primary Key:
invest_code
,snapshot_date
(composite key) - Columns:
market_cap_usd
,market_cap_local
,currency
,sp500_weight_percent
,sector
,industry
,source
,created_at
- Usage: Daily S&P 500 market capitalization tracking for 503 stocks
- Market Cap Calculation: Close price × shares outstanding / 1 billion (stored in billions USD)
- Weight Calculation:
(stock_market_cap / total_sp500_market_cap) × 100
for each date - GICS Classification (2025-10-07):
sector
: GICS Sector (11 categories: Information Technology, Health Care, Financials, Consumer Discretionary, Industrials, Consumer Staples, Communication Services, Energy, Utilities, Real Estate, Materials)industry
: GICS Sub-Industry (163 categories: Semiconductors, Biotechnology, etc.)- All 377,570 historical records updated to match GICS standard from Wikipedia
- Data Range: 3 years (753 trading days from 2022-10-04 to 2025-10-03)
- Example: invest_code='NVDA', snapshot_date='2025-10-03', market_cap_usd=4567.98, sp500_weight_percent=7.6724, sector='Information Technology', industry='Semiconductors'
- Time Zone:
created_at
stored in Korean time (UTC+9) usingCURRENT_TIMESTAMP + INTERVAL '9 hours'
Key Schema Patterns
- Composite Primary Keys: PostgreSQL supports multi-column primary keys for data integrity
- Bulk Upsert: Uses ON CONFLICT clause for efficient bulk updates
- Data Types: Float values stored as DECIMAL/NUMERIC for precision
- Logging: Custom
logger.py
with append mode (mode='a'
) and hierarchical directory structure (logs/yyyy/mm/
)- Supports multiple executions per day without overwriting previous logs
- Automatic directory creation for year/month organization
Schema Migration Files:
백엔드/table_ddl.sql
: Legacy KRW-based schema (pre-2025-10)백엔드/recreate_tables.sql
: Current USD-based schema with full table DROP and recreation- Execute via:
python AI가_수행하는_테스트_코드/execute_recreate_tables.py
Data Collection Patterns
Collection Frequency
- Exchange Rates: Daily collection of USD/KRW rates from exchangerate-api.com
- Stock Data: Daily collection covering recent 2-3 days to ensure weekend/holiday coverage
- Crypto Data: Daily collection covering recent 2-3 days for 24/7 market data
Error Handling Patterns
- Database Transactions: All bulk operations wrapped in try/catch with rollback capability
- Pandas Data Processing: Use
.item()
method to convert pandas Series to scalar values - Exchange Rate Fallback: Use most recent available rate if specific date unavailable
- Comprehensive Logging: All operations logged with timestamps and error details
Static Data Generation
- Purpose: Generate JSON files for frontend consumption to reduce database load
- Update Frequency: Daily via cron job at 1 AM
- S3 Upload: Automated upload to S3 bucket for CloudFront distribution
AWS Deployment Configuration
S3 + CloudFront Setup
- S3 Bucket:
if-invest
(configured for static website hosting) - CloudFront Distribution:
E67TOH4R1CV1U
(CDN for global content delivery) - Production URL:
https://whatif-invest.com
- Deployment Script:
deploy.bat
performs build → S3 sync → CloudFront invalidation - Critical S3 Sync Pattern (UPDATED 2025-10-12):
aws s3 sync dist/ s3://if-invest/ --delete --exact-timestamps --exclude "api/*_price_history.json" --exclude "api/sp500/**"
--delete
: Removes old build files from S3--exclude "api/*_price_history.json"
: Protects 97 backend-uploaded price history JSONs from deletion--exclude "api/sp500/**"
: CRITICAL - Protects 758 S&P 500 heatmap files from deletion- Why needed: Frontend deployment (npm run deploy) must NOT delete backend-generated data files
- Incident 2025-10-12: Missing
--exclude "api/sp500/**"
caused deletion of all 758 heatmap files, requiring full 3-year rebuild
- AWS CLI Required: Must be configured with appropriate IAM permissions for S3 and CloudFront
SPA Routing Configuration (Critical for React Router)
The application uses client-side routing via React Router, which requires special configuration on S3/CloudFront:
Problem: Direct URL access (e.g., https://whatif-invest.com/privacy-policy
) results in S3 404 errors because the file doesn't physically exist.
Solution: CloudFront Custom Error Responses redirect all 403/404 errors to index.html
with 200 status, allowing React Router to handle routing client-side.
CloudFront Custom Error Response Settings (required):
- 403 Forbidden → Response:
/index.html
with HTTP 200 - 404 Not Found → Response:
/index.html
with HTTP 200
Fallback: public/error.html
provides hash-based redirect fallback (not currently used with proper CloudFront setup)
App.tsx Routing: Includes wildcard route <Route path="*" element={<MainDashboard />} />
for catch-all handling
AWS IAM Requirements
For S3/CloudFront Deployment
Configure AWS CLI with a user having these permissions:
AmazonS3FullAccess
or specific bucket permissionsCloudFrontFullAccess
or invalidation permissions- Run
aws configure
to set up access keys and region (ap-northeast-2
for Seoul)
For Lambda Secure API Deployment
IAM User requires these permissions for Lambda deployment:
IAMFullAccess
(for creating Lambda execution roles)AWSLambda_FullAccess
(for Lambda function management)AmazonAPIGatewayAdministrator
(for API Gateway management)
For Static Data Upload (S3)
IAM Role or User requires these S3 permissions for uploading generated JSON files:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::if-invest/*"
]
}
]
}
AWS Lambda Secure API
Architecture
- Lambda Function:
if-invest-secure-api
(Python 3.9) - API Gateway:
c7zf9o2g6e
with REST API configuration - IAM Role:
lambda-s3-role
with S3 read permissions
Security Features
- Origin Validation: Validates request origin against allowed domains
- Rate Limiting: 100 requests per hour per IP address
- Bot Detection: Blocks requests with bot user agents
- CORS Handling: Proper CORS headers for browser compatibility
Deployment Process
- Create IAM role with S3 read permissions
- Deploy Lambda function with secure API proxy code
- Create API Gateway with Lambda integration
- Configure CORS and deploy API to production stage
- Update frontend with API Gateway URL
Manual Deployment
If automated deployment fails, follow these guides:
lambda/AWS_SETUP_GUIDE.md
- Step-by-step AWS setuplambda/DEPLOYMENT_CHECKLIST.md
- Verification checklistlambda/PERMISSION_ISSUE.md
- Permission troubleshooting