if_invest/CLAUDE.md
2025-10-12 02:11:49 +09:00

53 KiB
Raw Permalink Blame History

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 after npm run build

Backend (Python Data Collection)

Navigate to 백엔드/ directory:

PostgreSQL Version (Current Production)

  • Collect exchange rate data: python collect_exchange_rate.py (daily incremental) or python collect_exchange_rate_full_history.py (full history rebuild)
  • Collect stock daily data: python collect_stock_candle_1d.py (daily incremental) or python collect_stock_candle_full_history.py (full history rebuild)
  • Collect crypto daily data: python collect_coin_candle_1d.py (daily incremental) or python 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:
      1. Copies invest_product_list.json and exchange_rates.json to public/api/ (for frontend bundling)
      2. Uploads all 99 JSON files to S3 /api directory (including 97 price histories)
    • File protection: Price history JSONs in S3 are excluded from frontend deployment deletion

S&P 500 Heatmap Data Generation (2025-10)

  • Daily update (21 days): python generate_sp500_heatmap_json.py (automatically called by update_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 and DEPLOYMENT_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
  • 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" and data-full-width-responsive="true"
    • Component: GoogleAdSense.tsx replaced all placeholder AdSpace.tsx components
    • Environment Variables: .env contains production Client ID and Slot ID (1439731527)
  • 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 visualization
    • i18next (25.5.2) for internationalization with 10 language files
    • react-router-dom (7.9.3) for routing
    • axios (1.12.2) for HTTP requests
    • date-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
  • Database Connection: DBConn class in db_conn.py with bulk upsert capabilities

Data Flow Architecture

  1. 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)
  2. Database Storage: All data stored in PostgreSQL in USD with structured tables (invest_candles, invest_product_code, exchange_rates, stock_market_cap_history)
  3. Product Filtering: Investment product codes filtered by code_type ('STOCK'/'COIN') and use_yn ('Y') for active collection
  4. 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 histories
      • sp500/YYYY/MM/heatmap_YYYYMMDD.json - 753 S&P 500 heatmap files (3 years)
  5. Frontend Build: Vite copies public/api/ files to dist/api/ during build
  6. 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 frontend npm run deploy
  7. Secure API Proxy: AWS Lambda + API Gateway provides secure access to individual product price data from S3
  8. Client-Side Simulation: Frontend loads bundled product list and exchange rates, fetches detailed price data via Lambda API only when simulation requested
  9. 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) vs KRW-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)
  • 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 in db_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 and use_yn
    • Comprehensive error handling and transaction management
  • Logging: All database operations logged via custom logger.py

Critical Implementation Notes

Frontend Development

  • TypeScript: Use import type { TypeName } for type-only imports (required by verbatimModuleSyntax)
    • Import Locale type from date-fns/locale when using locale objects
  • 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() or console.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
  • 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
  • Internationalization: 10 languages with IP-based auto-detection via ipapi.co
    • geolocation.ts: Maps 43+ country codes to appropriate languages
    • useLanguageDetection.ts: Handles automatic detection and manual language switching
    • i18n/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}}일)" requires t('investmentSettings.dayOfMonth', { day: dayOfMonth })
  • Date Localization: All dates in charts and tables localized using date-fns with language-specific formats
    • ChartArea.tsx and InvestmentTableModal.tsx import all 10 locales from date-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)
  • 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) from utils/productNameUtils.ts
    • Korean users (i18n.language === 'ko'): Display code_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
  • 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):
        1. "Information Technology" (NOT "TECHNOLOGY")
        2. "Financials" (NOT "FINANCIAL")
        3. "Consumer Discretionary" (NOT "CONSUMER CYCLICAL")
        4. "Health Care" (NOT "HEALTHCARE" - note the space)
        5. "Industrials" (correct)
        6. "Consumer Staples" (NOT "CONSUMER DEFENSIVE")
        7. "Communication Services" (correct)
        8. "Energy" (correct)
        9. "Utilities" (correct)
        10. "Real Estate" (correct - note the space)
        11. "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 and invest_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)
    • 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
  • 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
  • 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
  • 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) via CURRENT_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

  1. Frontend Development: Work in if_invest/ directory with hot reload via npm run dev
  2. Backend Development: Work in 백엔드/ directory for production data collection
  3. Testing: Use backend_test/ directory for experimental data collection scripts
  4. Database Operations: Use DBConn class in db_conn.py for PostgreSQL operations
  5. 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):

  1. {TICKER}_candle_data_YYYYMMDD.csv - Historical OHLCV data from PostgreSQL
  2. {TICKER}_ai_prompt.py - Prompt template for Claude.ai analysis

2. Claude.ai Analysis Process

  1. Access: https://claude.ai
  2. Model: Claude 3.5 Sonnet with Extended Thinking
  3. Settings: Enable "Thinking" + "Research" features
  4. Input:
    • Attach CSV file
    • Run python {TICKER}_ai_prompt.py to get prompt text
    • Paste prompt into Claude.ai
  5. 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:

  1. 3-year weekly predictions (156 weeks total) - for chart visualization
  2. Evidence-based reasoning - all predictions must cite news/analyst reports with URLs
  3. Multi-source validation - latest news, analyst ratings, financial metrics, historical patterns
  4. 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 options
  • 01_AI_기반_투자_예측_서비스_설계.md - Detailed AI prediction service design
  • generate_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 uses selectedCurrency 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:
    1. Add key to ko.json: "recordCount": "총 {{count}}건의 투자 기록"
    2. Use in component: t('table.recordCount', { count: records.length })
    3. Replicate to all language files (ja, zh-CN, es, pt, fr, de, vi, id, en)

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

  1. .content-area and .sidebar-area must have min-width: 0 and min-height: 0 in base styles

    • Default min-width: 700px or min-height: 600px breaks flex layout on mobile
    • These prevent the mobile flex-direction: column from working properly
  2. .chart-area-main must have height: auto (NOT height: 100%)

    • height: 100% causes ResponsiveContainer to fail rendering when parent height is not explicit
    • Set to auto in base styles, then override with specific min-height values in media queries
  3. .chart-container must have flex: none in mobile media queries

    • Default flex: 1 causes height calculation issues on mobile
    • Must use !important flag to override base styles

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:

  1. Check .content-area base styles have min-width: 0 and min-height: 0
  2. Check .chart-area-main base style has height: auto (not height: 100%)
  3. Verify media queries use !important flags for overrides
  4. Ensure .chart-container has flex: none !important in mobile media queries
  5. 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:
    1. Exact date match
    2. Nearest previous date
    3. 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

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 notes
    • is_sp500 varchar(1): 'Y' for S&P 500 stocks, NULL otherwise
    • sector 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') and use_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) using CURRENT_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 permissions
  • CloudFrontFullAccess 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

  1. Create IAM role with S3 read permissions
  2. Deploy Lambda function with secure API proxy code
  3. Create API Gateway with Lambda integration
  4. Configure CORS and deploy API to production stage
  5. Update frontend with API Gateway URL

Manual Deployment

If automated deployment fails, follow these guides:

  • lambda/AWS_SETUP_GUIDE.md - Step-by-step AWS setup
  • lambda/DEPLOYMENT_CHECKLIST.md - Verification checklist
  • lambda/PERMISSION_ISSUE.md - Permission troubleshooting