From dbcfc65752ac35666f282084972b1243a9f5946e Mon Sep 17 00:00:00 2001 From: Deep Koluguri Date: Sat, 13 Dec 2025 00:42:54 -0500 Subject: [PATCH] updated api config and url --- PROXMOX_DEPLOYMENT.md | 429 +++++++++++++++++- frontend/src/components/charts/PriceChart.jsx | 3 +- .../src/components/dashboard/AlertsFeed.jsx | 4 +- .../dashboard/PerformanceTrackingPanel.jsx | 3 +- .../dashboard/PhaseClassifierPanel.jsx | 5 +- .../src/components/dashboard/ScannerPanel.jsx | 3 +- .../src/components/dashboard/Watchlist.jsx | 3 +- frontend/src/hooks/useAIAnalysis.js | 3 +- frontend/src/hooks/useOptionsFlow.js | 3 +- frontend/src/hooks/useWebSocket.js | 5 +- 10 files changed, 432 insertions(+), 29 deletions(-) diff --git a/PROXMOX_DEPLOYMENT.md b/PROXMOX_DEPLOYMENT.md index 1e27d82..e8c3261 100644 --- a/PROXMOX_DEPLOYMENT.md +++ b/PROXMOX_DEPLOYMENT.md @@ -11,10 +11,11 @@ Complete guide for deploying the Institutional Trader platform on a Proxmox serv 5. [Database Configuration](#5-database-configuration) 6. [Systemd Services](#6-systemd-services) 7. [Nginx Configuration](#7-nginx-configuration) -8. [SSL Certificates](#8-ssl-certificates) -9. [Database Access for Friend](#9-database-access-for-friend) -10. [Monitoring & Maintenance](#10-monitoring--maintenance) -11. [Troubleshooting](#11-troubleshooting) +8. [DNS Configuration](#8-dns-configuration) +9. [SSL Certificates](#9-ssl-certificates) +10. [Database Access for Friend](#10-database-access-for-friend) +11. [Monitoring & Maintenance](#11-monitoring--maintenance) +12. [Troubleshooting](#12-troubleshooting) --- @@ -206,6 +207,8 @@ nano .env.production ``` **Frontend `.env.production` configuration:** + +**⚠️ Critical:** The frontend must have a `.env.production` file with the correct API URL, otherwise it will try to connect to `localhost:3010` which won't work in production. ```env VITE_API_URL=https://api.yourdomain.com VITE_WS_URL=wss://api.yourdomain.com @@ -333,6 +336,7 @@ Type=simple User=root WorkingDirectory=/opt/institutional_trader/backend/python_service Environment="PATH=/opt/institutional_trader/backend/python_service/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +EnvironmentFile=/opt/institutional_trader/backend/python_service/.env ExecStart=/opt/institutional_trader/backend/python_service/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8010 Restart=always RestartSec=10 @@ -343,6 +347,8 @@ StandardError=journal WantedBy=multi-user.target ``` +**Note:** The `EnvironmentFile` directive is optional - the service will also load `.env` automatically via `load_dotenv()` in the code. However, adding it explicitly ensures environment variables are available even if the code path changes. + Enable and start: ```bash sudo systemctl daemon-reload @@ -479,7 +485,96 @@ server { } ``` -### 7.2 Enable Site +### 7.2 Multi-Container Setup (Nginx on Separate Container) + +If you're running nginx on a separate container/VM that proxies to your application containers: + +**Example configuration for proxying to another Proxmox container:** + +```nginx +server { + listen 443 ssl http2; + server_name traderideas.deepteklabs.com; + + ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem; + + # Security Headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + + # Backend API Routes + location /api/ { + proxy_pass http://192.168.8.151:3000/api/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + proxy_buffering off; + } + + # WebSocket Support (if using WebSockets) + location /ws { + proxy_pass http://192.168.8.151:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 86400; # 24 hours for long-lived connections + } + + # Health Check + location /health { + proxy_pass http://192.168.8.151:3000/health; + access_log off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + + # Frontend (served from application container) + location / { + proxy_pass http://192.168.8.151:8080/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_hide_header Cache-Control; + add_header Cache-Control "no-cache, no-store, must-revalidate" always; + } + + # Static assets with caching + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|otf|map)$ { + proxy_pass http://192.168.8.151:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } +} +``` + +**Important notes for multi-container setup:** +- Replace `192.168.8.151` with your application container's IP +- Ensure containers can communicate (same network/bridge) +- Port 3000 = Backend API, Port 8080 = Frontend (adjust as needed) +- Test connectivity: `curl http://192.168.8.151:3000/health` from nginx container + +### 7.3 Enable Site ```bash # Create symlink @@ -494,19 +589,179 @@ sudo systemctl reload nginx --- -## 8. SSL Certificates +## 8. DNS Configuration -### 8.1 Install Certbot +**⚠️ Important:** Before setting up SSL certificates, you must configure DNS records pointing to your server. + +### 8.1 Find Your Server's Public IP Address + +```bash +# On your server, find the public IP +curl ifconfig.me +# Or +hostname -I +# Or check in Proxmox Web UI: Datacenter → Your Node → Network +``` + +### 8.2 Configure DNS A Records + +Go to your domain registrar's DNS management panel (where you registered `traderideas.deepteklabs.com`) and add these A records: + +| Type | Name | Value | TTL | +|------|------|-------|-----| +| A | `@` (or blank) | `` | 3600 | +| A | `www` | `` | 3600 | +| A | `api` | `` | 3600 | + +**Example for `traderideas.deepteklabs.com`:** +- `traderideas.deepteklabs.com` → `` (A record with name `@` or blank) +- `www.traderideas.deepteklabs.com` → `` (A record with name `www`) +- `api.traderideas.deepteklabs.com` → `` (A record with name `api`) + +### 8.3 Verify DNS Propagation + +Wait 5-15 minutes for DNS to propagate, then verify: + +```bash +# Check if DNS records are resolving +dig traderideas.deepteklabs.com +short +dig www.traderideas.deepteklabs.com +short +dig api.traderideas.deepteklabs.com +short + +# All should return your server's IP address + +# Alternative: Use nslookup +nslookup traderideas.deepteklabs.com +nslookup www.traderideas.deepteklabs.com +nslookup api.traderideas.deepteklabs.com + +# Or use online tools: +# - https://dnschecker.org +# - https://www.whatsmydns.net +``` + +**Common DNS Providers:** +- **Cloudflare**: Dashboard → DNS → Records → Add record +- **Namecheap**: Domain List → Manage → Advanced DNS → Add New Record +- **GoDaddy**: DNS Management → Add Record +- **Google Domains**: DNS → Custom Records → Add Record + +### 8.4 Test Domain Accessibility + +Once DNS is propagated, test that domains are reachable: + +```bash +# From your server +curl -I http://traderideas.deepteklabs.com +curl -I http://www.traderideas.deepteklabs.com +curl -I http://api.traderideas.deepteklabs.com + +# Should return HTTP responses (even if 502/503, that's OK - means DNS is working) +``` + +### 8.5 Cloudflare Proxy (Orange Cloud) + +**If your domain uses Cloudflare proxy (orange cloud icon):** + +When DNS resolves to Cloudflare IPs (like `104.21.x.x` or `172.67.x.x`), your domain is behind Cloudflare proxy. This affects SSL certificate setup: + +**Check if using Cloudflare proxy:** +```bash +dig traderideas.deepteklabs.com +short +# If returns Cloudflare IPs (104.x.x.x, 172.x.x.x), proxy is enabled +``` + +**Options for SSL with Cloudflare:** + +1. **Use DNS Challenge (Recommended)** - Works with proxy enabled +2. **Temporarily Disable Proxy** - Get certs, then re-enable proxy +3. **Use Cloudflare SSL** - Let Cloudflare handle SSL (easiest) + +See Section 9.2 for detailed instructions. + +**⚠️ Only proceed to SSL setup once DNS records are working!** + +--- + +## 9. SSL Certificates + +### 9.1 Install Certbot ```bash sudo apt install -y certbot python3-certbot-nginx ``` -### 8.2 Obtain SSL Certificate +### 9.2 Obtain SSL Certificate + +**⚠️ Prerequisites:** +- DNS A records must be configured and propagated (see Section 8) +- Domains must resolve to your server's IP (or Cloudflare if using proxy) +- Port 80 must be accessible from the internet (for HTTP challenge) OR DNS API access (for DNS challenge) + +**⚠️ Important:** If your nginx config already references SSL certificates that don't exist, you need to fix this first. + +**Check if using Cloudflare proxy:** +```bash +dig traderideas.deepteklabs.com +short +# If returns Cloudflare IPs (104.x.x.x, 172.x.x.x), you're using Cloudflare proxy +``` + +**If using Cloudflare Proxy, use Option D (DNS Challenge) or Option E (Cloudflare SSL)** + +**Option A: Use Standalone Mode (Works if NOT using Cloudflare proxy)** + +```bash +# Stop nginx temporarily +sudo systemctl stop nginx + +# Get certificates using standalone mode +sudo certbot certonly --standalone -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com + +# Start nginx again +sudo systemctl start nginx + +# Now certbot can update the nginx config +sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com +``` + +**Option B: Temporarily Comment Out SSL in Nginx Config** + +```bash +# Edit nginx config +sudo nano /etc/nginx/sites-available/institutional-trader + +# Temporarily comment out SSL lines: +# - Comment out: listen 443 ssl http2; +# - Comment out: ssl_certificate and ssl_certificate_key lines +# - Change: listen 443 ssl http2; to: listen 80; + +# Example temporary config (HTTP only): +# server { +# listen 80; +# server_name traderideas.deepteklabs.com; +# # ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem; +# # ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem; +# ... +# } + +# Test and reload +sudo nginx -t +sudo systemctl reload nginx + +# Now get certificates (certbot will automatically update the config) +sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com + +# Certbot will automatically: +# - Get the certificates +# - Update your nginx config to use them +# - Add SSL redirects +``` + +**Option C: Use Certbot with Nginx Plugin (If config is clean and NOT using Cloudflare proxy)** ```bash # Replace with your actual domain -sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com -d api.yourdomain.com +sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com ``` Follow the prompts: @@ -514,7 +769,85 @@ Follow the prompts: - Agree to terms - Choose whether to redirect HTTP to HTTPS (recommended: Yes) -### 8.3 Auto-Renewal +**Option D: DNS Challenge (Recommended for Cloudflare proxy)** + +If your domain is behind Cloudflare proxy, use DNS challenge: + +```bash +# Install Cloudflare plugin for certbot +sudo apt install -y python3-pip +sudo pip3 install certbot-dns-cloudflare + +# Create Cloudflare API token directory +sudo mkdir -p /etc/letsencrypt +sudo chmod 700 /etc/letsencrypt + +# Create Cloudflare credentials file +sudo nano /etc/letsencrypt/cloudflare.ini +``` + +Add your Cloudflare API token: +```ini +# Cloudflare API token (get from: Cloudflare Dashboard → My Profile → API Tokens → Create Token) +# Permissions needed: Zone:Zone:Read, Zone:DNS:Edit +dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN +``` + +```bash +# Secure the credentials file +sudo chmod 600 /etc/letsencrypt/cloudflare.ini + +# Get certificates using DNS challenge +sudo certbot certonly \ + --dns-cloudflare \ + --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \ + -d traderideas.deepteklabs.com \ + -d www.traderideas.deepteklabs.com \ + -d api.traderideas.deepteklabs.com + +# Update nginx config manually (certbot won't auto-update with DNS challenge) +sudo nano /etc/nginx/sites-available/institutional-trader +# Update ssl_certificate paths to: +# ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem; +# ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem; + +sudo nginx -t +sudo systemctl reload nginx +``` + +**Option E: Use Cloudflare SSL (Easiest with Cloudflare proxy)** + +If using Cloudflare proxy, you can let Cloudflare handle SSL: + +1. **In Cloudflare Dashboard:** + - Go to SSL/TLS → Overview + - Set encryption mode to **"Full"** or **"Full (strict)"** + - Cloudflare will automatically provide SSL certificates + +2. **On your server, use self-signed or Cloudflare Origin Certificate:** + ```bash + # Generate self-signed certificate (Cloudflare will accept it) + sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout /etc/ssl/private/nginx-selfsigned.key \ + -out /etc/ssl/certs/nginx-selfsigned.crt + + # Update nginx config to use self-signed cert + sudo nano /etc/nginx/sites-available/institutional-trader + # Change to: + # ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; + # ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; + + sudo nginx -t + sudo systemctl reload nginx + ``` + +3. **Or get Cloudflare Origin Certificate:** + - Cloudflare Dashboard → SSL/TLS → Origin Server → Create Certificate + - Copy certificate and key + - Save to `/etc/ssl/certs/cloudflare-origin.crt` and `/etc/ssl/private/cloudflare-origin.key` + - Update nginx config to use these files + +### 9.3 Auto-Renewal Certbot sets up auto-renewal automatically. Test it: @@ -524,7 +857,7 @@ sudo certbot renew --dry-run --- -## 9. Database Access for Friend +## 10. Database Access for Friend ### Option A: Supabase (Recommended) @@ -634,7 +967,7 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO friend_reado --- -## 10. Monitoring & Maintenance +## 11. Monitoring & Maintenance ### 10.1 Health Checks @@ -707,7 +1040,7 @@ sudo -u postgres psql institutional_trader < backup_20240101.sql --- -## 11. Troubleshooting +## 12. Troubleshooting ### Backend Won't Start @@ -725,16 +1058,80 @@ node -e "import('./src/db.js').then(m => m.testConnection())" ### Python Service Won't Start +**Step 1: Check detailed error logs** ```bash -# Check logs -sudo journalctl -u institutional-trader-python -n 50 +# View recent logs with full error messages +sudo journalctl -u institutional-trader-python -n 100 --no-pager -# Test manually +# Follow logs in real-time +sudo journalctl -u institutional-trader-python -f +``` + +**Step 2: Verify systemd service file has correct port** +```bash +# Check current service file +sudo cat /etc/systemd/system/institutional-trader-python.service + +# If port is 8000, update it to 8010: +sudo nano /etc/systemd/system/institutional-trader-python.service +# Change: --port 8000 to --port 8010 +# Then reload and restart: +sudo systemctl daemon-reload +sudo systemctl restart institutional-trader-python +``` + +**Step 3: Test manually to see actual error** +```bash cd /opt/institutional_trader/backend/python_service source venv/bin/activate + +# Check if .env file exists and has correct DB config +cat .env + +# Test startup manually uvicorn main:app --host 0.0.0.0 --port 8010 ``` +**Step 4: Common issues and fixes** + +**Database connection timeout:** +- The service now has a 10-second timeout and will start even if DB is temporarily unavailable +- Check database is reachable: `psql -h -U -d institutional_trader` +- Verify `.env` file in `backend/python_service/` has correct database credentials + +**Port already in use:** +```bash +# Check if port 8010 is in use +sudo netstat -tlnp | grep 8010 +# Or +sudo lsof -i :8010 + +# Kill process if needed +sudo kill -9 +``` + +**Missing dependencies:** +```bash +cd /opt/institutional_trader/backend/python_service +source venv/bin/activate +pip install -r requirements.txt +``` + +**Step 5: Verify backend .env has correct Python service URL** +```bash +# Check backend .env +cat /opt/institutional_trader/backend/.env | grep PYTHON_SERVICE_URL + +# Should be: +# PYTHON_SERVICE_URL=http://localhost:8010 + +# If not, update it: +nano /opt/institutional_trader/backend/.env +# Add or update: PYTHON_SERVICE_URL=http://localhost:8010 +# Then restart backend: +sudo systemctl restart institutional-trader-backend +``` + ### Nginx Errors ```bash diff --git a/frontend/src/components/charts/PriceChart.jsx b/frontend/src/components/charts/PriceChart.jsx index feb2bc9..5e65cda 100644 --- a/frontend/src/components/charts/PriceChart.jsx +++ b/frontend/src/components/charts/PriceChart.jsx @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { createChart } from 'lightweight-charts'; +import { getApiUrl } from '@/config/api'; export default function PriceChart({ symbol, flowData }) { const chartContainerRef = useRef(); @@ -175,7 +176,7 @@ export default function PriceChart({ symbol, flowData }) { async function fetchPriceData(symbol, timeframe) { try { const response = await fetch( - `http://localhost:3010/api/prices/${symbol}?timeframe=${timeframe}` + `${getApiUrl(`/api/prices/${symbol}`)}?timeframe=${timeframe}` ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); diff --git a/frontend/src/components/dashboard/AlertsFeed.jsx b/frontend/src/components/dashboard/AlertsFeed.jsx index d46481f..a49a443 100644 --- a/frontend/src/components/dashboard/AlertsFeed.jsx +++ b/frontend/src/components/dashboard/AlertsFeed.jsx @@ -26,7 +26,7 @@ export default function AlertsFeed() { } // WebSocket connection for real-time alerts - // Vite proxy handles /ws -> ws://localhost:3010 + // Uses relative URL which will be proxied by nginx or use configured WS URL const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${wsProtocol}//${window.location.host}/ws/alerts`; @@ -75,7 +75,7 @@ export default function AlertsFeed() { const fetchAlerts = async () => { try { - let url = '/api/alerts/recent'; + let url = getApiUrl('/api/alerts/recent'); if (useHistorical && historicalDate) { const params = new URLSearchParams({ date: historicalDate, diff --git a/frontend/src/components/dashboard/PerformanceTrackingPanel.jsx b/frontend/src/components/dashboard/PerformanceTrackingPanel.jsx index 17936a4..c10f485 100644 --- a/frontend/src/components/dashboard/PerformanceTrackingPanel.jsx +++ b/frontend/src/components/dashboard/PerformanceTrackingPanel.jsx @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react'; import { Badge } from '../ui/Badge'; import { TrendingUp, TrendingDown, Target, BarChart3 } from 'lucide-react'; +import { getApiUrl } from '@/config/api'; export default function PerformanceTrackingPanel() { const [stats, setStats] = useState({ @@ -24,7 +25,7 @@ export default function PerformanceTrackingPanel() { useEffect(() => { const fetchStats = async () => { try { - const response = await fetch('http://localhost:3010/api/performance/stats'); + const response = await fetch(getApiUrl('/api/performance/stats')); // Check if response is ok if (!response.ok) { diff --git a/frontend/src/components/dashboard/PhaseClassifierPanel.jsx b/frontend/src/components/dashboard/PhaseClassifierPanel.jsx index 79eaf97..c4c8340 100644 --- a/frontend/src/components/dashboard/PhaseClassifierPanel.jsx +++ b/frontend/src/components/dashboard/PhaseClassifierPanel.jsx @@ -2,8 +2,7 @@ import { useEffect, useState } from 'react'; import { DataTable } from '@/components/ui/data-table'; import { Badge } from '@/components/ui/Badge'; import { Button } from '@/components/ui/button'; - -const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3010'; +import { getApiUrl } from '@/config/api'; export default function PhaseClassifierPanel() { const [data, setData] = useState([]); @@ -16,7 +15,7 @@ export default function PhaseClassifierPanel() { const fetchData = async () => { try { setLoading(true); - const response = await fetch(`${API_BASE_URL}/api/options/phase-classifier`); + const response = await fetch(getApiUrl('/api/options/phase-classifier')); const result = await response.json(); if (result.success) { diff --git a/frontend/src/components/dashboard/ScannerPanel.jsx b/frontend/src/components/dashboard/ScannerPanel.jsx index ef5eb58..c4fbc20 100644 --- a/frontend/src/components/dashboard/ScannerPanel.jsx +++ b/frontend/src/components/dashboard/ScannerPanel.jsx @@ -4,6 +4,7 @@ import { Badge } from '@/components/ui/Badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Star, TrendingUp, TrendingDown, Calendar, Clock } from 'lucide-react'; +import { getApiUrl } from '@/config/api'; export default function ScannerPanel() { const [scanResults, setScanResults] = useState([]); @@ -34,7 +35,7 @@ export default function ScannerPanel() { const runScan = async () => { setLoading(true); try { - let url = 'http://localhost:3010/api/scanner/multi-signal'; + let url = getApiUrl('/api/scanner/multi-signal'); if (useHistorical && historicalDate) { const params = new URLSearchParams({ date: historicalDate }); if (historicalTime) { diff --git a/frontend/src/components/dashboard/Watchlist.jsx b/frontend/src/components/dashboard/Watchlist.jsx index b3467b8..b10e8c9 100644 --- a/frontend/src/components/dashboard/Watchlist.jsx +++ b/frontend/src/components/dashboard/Watchlist.jsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react'; import { X } from 'lucide-react'; +import { getApiUrl } from '@/config/api'; export default function Watchlist() { const [watchlist, setWatchlist] = useState([]); @@ -24,7 +25,7 @@ export default function Watchlist() { try { // Fetch prices for all watchlist symbols const symbols = watchlist.join(','); - const response = await fetch(`http://localhost:3010/api/prices?symbols=${symbols}`); + const response = await fetch(`${getApiUrl('/api/prices')}?symbols=${symbols}`); const data = await response.json(); if (data.success && data.data) { diff --git a/frontend/src/hooks/useAIAnalysis.js b/frontend/src/hooks/useAIAnalysis.js index 8a3e73d..34801df 100644 --- a/frontend/src/hooks/useAIAnalysis.js +++ b/frontend/src/hooks/useAIAnalysis.js @@ -1,4 +1,5 @@ import { useState, useCallback } from 'react'; +import { getApiUrl } from '@/config/api'; export function useAIAnalysis() { const [loading, setLoading] = useState(false); @@ -10,7 +11,7 @@ export function useAIAnalysis() { setError(null); try { - const response = await fetch('http://localhost:3010/api/options/ai-analysis', { + const response = await fetch(getApiUrl('/api/options/ai-analysis'), { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/hooks/useOptionsFlow.js b/frontend/src/hooks/useOptionsFlow.js index 9b13313..fa35615 100644 --- a/frontend/src/hooks/useOptionsFlow.js +++ b/frontend/src/hooks/useOptionsFlow.js @@ -1,4 +1,5 @@ import { useState, useEffect, useCallback, useRef } from 'react'; +import { getApiUrl } from '@/config/api'; export function useOptionsFlow({ autoRefresh = false, interval = 30000, ...filters }) { const [data, setData] = useState(null); @@ -32,7 +33,7 @@ export function useOptionsFlow({ autoRefresh = false, interval = 30000, ...filte ) }); - const response = await fetch(`http://localhost:3010/api/options/flow?${params}`); + const response = await fetch(`${getApiUrl('/api/options/flow')}?${params}`); const result = await response.json(); if (result.success) { diff --git a/frontend/src/hooks/useWebSocket.js b/frontend/src/hooks/useWebSocket.js index 94a7d50..6a1b075 100644 --- a/frontend/src/hooks/useWebSocket.js +++ b/frontend/src/hooks/useWebSocket.js @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from "react"; import { useAppStore } from "../store/useAppStore"; +import { getWsUrl } from "@/config/api"; export function useWebSocket(url = "/ws/flow") { const [messages, setMessages] = useState([]); @@ -9,8 +10,8 @@ export function useWebSocket(url = "/ws/flow") { const addAlert = useAppStore((state) => state.addAlert); useEffect(() => { - // Create WebSocket connection (use proxy through Vite dev server) - const ws = new WebSocket(`ws://localhost:5010${url}`); + // Create WebSocket connection using configured WS URL + const ws = new WebSocket(getWsUrl(url)); wsRef.current = ws; ws.onopen = () => {