Skip to content

Commit a82f79d

Browse files
authored
fix: cors for chat agent (#36)
* fix: cors for chat agent * feat: clean up routing and use proxy in all environments * chore: clean up vite config
1 parent b2a10fd commit a82f79d

29 files changed

Lines changed: 446 additions & 502 deletions

CLAUDE.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,54 @@ src/components/
295295
- React Context for local/auth state
296296
- Form state via React Hook Form
297297

298+
### API Routing Pattern
299+
300+
**Service-Prefixed Routes** (Unified Architecture):
301+
302+
All API requests use service-prefixed paths that are proxied by Vite to backend services:
303+
304+
```
305+
/server/* → Backend API server
306+
/chat/* → Chat agent service
307+
/rpc/* → Ethereum RPC node
308+
```
309+
310+
**Key Files**:
311+
- `src/shared/config/api-routes.ts` - Single source of truth for all API routes
312+
- `vite.config.ts` - Proxy configuration (strips prefixes before forwarding)
313+
- `src/shared/config/runtime.ts` - Minimal config (only environment flags)
314+
315+
**Example Usage**:
316+
```typescript
317+
import { API_PATHS } from '@/shared/config/api-routes';
318+
319+
// Backend API call
320+
fetch(`${API_PATHS.SERVER_API}/auth/login`); // → /server/api/v1/auth/login
321+
322+
// Chat agent call
323+
fetch(API_PATHS.CHAT_STREAM); // → /chat/api/v1/chat/stream
324+
325+
// RPC call (uses proxy in dev, external HTTPS in production)
326+
new Web3Provider(DEFAULT_ETHEREUM_RPC_URL); // → /rpc or https://...
327+
```
328+
329+
**Environment Variables**:
330+
- **Runtime** (application code):
331+
- `VITE_SERVER_ENVIRONMENT`: 'local' | 'staging' | 'sandbox' | 'production'
332+
- `VITE_ETHEREUM_RPC_URL`: Optional external RPC URL (production only)
333+
334+
- **Vite Config** (proxy targets):
335+
- `VITE_SERVER_URL`: Backend service URL (for proxy)
336+
- `VITE_CHAT_AGENT_URL`: Chat agent service URL (for proxy)
337+
- `VITE_ETHEREUM_RPC_URL`: RPC node URL (for proxy)
338+
339+
**Benefits**:
340+
- Single source of truth prevents path inconsistencies
341+
- Type-safe route references
342+
- No hardcoded URLs in API clients
343+
- Vite proxy handles dev/production routing automatically
344+
- Avoids mixed content errors (HTTPS page → HTTP API)
345+
298346
## Important Notes
299347

300348
### TypeScript Configuration

Dockerfile

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,32 @@ COPY <<EOF /docker-entrypoint.sh
4848

4949
# Simple startup logging
5050
echo "🚀 Starting Unified Arda Platform with Vite Preview Server"
51-
echo "Backend: \${VITE_SERVER_URL:-http://localhost:8080}"
52-
echo "Chat Agent: \${VITE_CHAT_AGENT_URL:-http://localhost:3002}"
53-
echo "Environment: \${VITE_SERVER_ENVIRONMENT:-production}"
51+
echo "📋 Configuration:"
52+
echo " - Environment: \${VITE_SERVER_ENVIRONMENT:-production}"
53+
echo " - RPC URL: \${VITE_ETHEREUM_RPC_URL:-(using /rpc proxy)}"
54+
echo ""
55+
echo "📡 Proxy Configuration (vite.config.ts):"
56+
echo " - /server/* -> Backend service"
57+
echo " - /chat/* -> Chat agent service"
58+
echo " - /rpc/* -> Ethereum RPC"
5459

5560
# Inject environment variables into the built app
61+
#
62+
# SIMPLIFIED CONFIGURATION:
63+
# =========================
64+
# Only environment flags and optional external endpoints.
65+
# All API routing uses service-prefixed paths proxied by Vite:
66+
# - /server/* → Backend API (see vite.config.ts)
67+
# - /chat/* → Chat agent (see vite.config.ts)
68+
# - /rpc/* → Ethereum RPC (see vite.config.ts)
69+
#
70+
# Environment variables (injected at runtime):
71+
# - VITE_SERVER_ENVIRONMENT: Environment flag (local/staging/sandbox/production)
72+
# - VITE_ETHEREUM_RPC_URL: Optional external HTTPS RPC endpoint (production only)
5673
cat > /app/dist/env-config.js << EOL
5774
window.__ENV__ = {
58-
VITE_SERVER_URL: "\${VITE_SERVER_URL:-http://arda-credit_server:8080}",
5975
VITE_SERVER_ENVIRONMENT: "\${VITE_SERVER_ENVIRONMENT:-production}",
60-
VITE_CHAT_AGENT_URL: "\${VITE_CHAT_AGENT_URL:-http://arda-credit_chat-agent:3002}",
61-
VITE_ETHEREUM_RPC_URL: "\${VITE_ETHEREUM_RPC_URL:-http://127.0.0.1:8545}"
76+
VITE_ETHEREUM_RPC_URL: "\${VITE_ETHEREUM_RPC_URL:-}"
6277
};
6378
EOL
6479

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,17 @@ cp apps/idr/.env.example apps/idr/.env
130130
```
131131

132132
Update the `.env` files with your configuration:
133-
- `VITE_API_URL`: Backend API endpoint
133+
- `VITE_SERVER_URL`: Backend API endpoint (empty string in production for relative paths)
134+
- `VITE_CHAT_AGENT_URL`: Chat agent endpoint (empty string in production for relative paths)
134135
- `VITE_CREDIT_APP_URL`: Credit App URL (for Platform redirects)
135136
- `VITE_IDR_URL`: IDR URL (for Platform redirects)
136137

138+
> **📖 Important**: See [URL Configuration Guide](./docs/URL_CONFIGURATION.md) for detailed information about our unified URL pattern, including:
139+
> - How empty URLs enable relative paths in production
140+
> - Vite proxy configuration for development and production
141+
> - Deployment configurations for Docker, Kubernetes, and cloud platforms
142+
> - Troubleshooting mixed content errors
143+
137144
### Development
138145

139146
#### Run All Applications

docker-compose.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ services:
1414
- arda-network
1515
restart: unless-stopped
1616
environment:
17+
# Environment configuration for Vite proxy targets and runtime
18+
# These env vars are used by vite.config.ts to configure proxy routing
19+
# Application code uses service-prefixed paths (/server, /chat, /rpc)
1720
- VITE_SERVER_URL=${VITE_SERVER_URL:-http://localhost:8080}
18-
- VITE_SERVER_ENVIRONMENT=${VITE_SERVER_ENVIRONMENT:-production}
1921
- VITE_CHAT_AGENT_URL=${VITE_CHAT_AGENT_URL:-http://localhost:3002}
2022
- VITE_ETHEREUM_RPC_URL=${VITE_ETHEREUM_RPC_URL:-http://127.0.0.1:8545}
23+
- VITE_SERVER_ENVIRONMENT=${VITE_SERVER_ENVIRONMENT:-local}
2124
env_file:
2225
- .env
2326
healthcheck:

src/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,6 @@ function AppContent() {
208208
{isAuthenticated && (
209209
<ChatWidget
210210
context={appContext}
211-
apiEndpoint={getConfig().CHAT_AGENT_URL}
212211
authToken={localStorage.getItem('arda_token') || undefined}
213212
contextData={chatContextData}
214213
/>

src/credit/hooks/useNetworkConfig.ts

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/credit/utils/blockchain.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// Blockchain utility functions for transaction links and formatting
22
import { getConfig } from '../../shared/config/runtime';
3+
import { API_ROUTES } from '../../shared/config/api-routes';
34

45
/**
56
* Default Ethereum RPC URL
6-
* Uses runtime config or falls back to local Anvil devnet
7+
*
8+
* Priority:
9+
* 1. Runtime config (for production external HTTPS endpoints)
10+
* 2. Proxy path /rpc (for development/staging with local nodes)
711
*/
8-
export const DEFAULT_ETHEREUM_RPC_URL = getConfig().ETHEREUM_RPC_URL;
12+
export const DEFAULT_ETHEREUM_RPC_URL = getConfig().ETHEREUM_RPC_URL || API_ROUTES.RPC;
913

1014
export const BLOCKCHAIN_NETWORKS = {
1115
mainnet: {

src/credit/utils/tokenHandler.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,11 @@ export class TokenHandler {
8888
}
8989

9090
/**
91-
* Redirect to Platform for authentication
91+
* Redirect to login page (unified app - no longer redirects to separate platform)
9292
*/
9393
static redirectToPlatform(): void {
94-
const { getConfig } = require('../config/runtime');
95-
const platformUrl = getConfig().PLATFORM_URL;
96-
const returnUrl = window.location.href;
97-
window.location.href = `${platformUrl}?return_to=${encodeURIComponent(returnUrl)}`;
94+
const returnUrl = window.location.pathname + window.location.search;
95+
window.location.href = `/auth/login?return_to=${encodeURIComponent(returnUrl)}`;
9896
}
9997

10098
/**

src/idr/lib/api.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/**
22
* IDR App API Client
3-
* Uses shared @arda/api-client package
3+
* Uses shared @arda/api-client package with service-prefixed routing
4+
*
5+
* All API requests use /server prefix which is proxied by Vite to the backend service.
6+
* See: src/shared/config/api-routes.ts for route definitions
7+
* See: vite.config.ts for proxy configuration
48
*/
59

610
import { createArdaAPI } from '@arda/api-client';
711
import type { ArdaAPI } from '@arda/api-client';
8-
import { getConfig } from '../../shared/config/runtime';
912

1013
// Get auth token from localStorage
1114
function getAuthToken(): string | null {
@@ -40,8 +43,9 @@ function handleAuthError(): void {
4043
}
4144

4245
// Create and export the API client
46+
// baseURL is empty - API paths use /server prefix which Vite proxy handles
4347
export const api: ArdaAPI = createArdaAPI({
44-
baseURL: getConfig().SERVER_URL,
48+
baseURL: '',
4549
getAuthToken,
4650
onAuthError: handleAuthError,
4751
enableLogging: true,

src/idr/lib/chatAgent.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
/**
22
* Chat Agent API Client for IDR
33
* Handles communication with the chat-agent service for AI-powered document analysis
4+
*
5+
* Uses /chat prefix which is proxied by Vite to the chat agent service.
6+
* See: src/shared/config/api-routes.ts for route definitions
7+
* See: vite.config.ts for proxy configuration
48
*/
59

6-
import { getConfig } from '../../shared/config/runtime';
10+
import { API_PATHS } from '../../shared/config/api-routes';
711

8-
const API_ENDPOINT = getConfig().CHAT_AGENT_URL;
12+
const API_ENDPOINT = API_PATHS.CHAT_API;
913

1014
export interface ProgressEvent {
1115
type: 'tool_start' | 'tool_complete' | 'iteration' | 'progress' | 'text_chunk';
@@ -63,7 +67,7 @@ export async function sendChatMessage(
6367
request: ChatRequest,
6468
onProgress?: (event: ProgressEvent) => void
6569
): Promise<ChatResponse> {
66-
const STREAM_ENDPOINT = API_ENDPOINT.replace('/chat', '/chat/stream');
70+
const STREAM_ENDPOINT = API_PATHS.CHAT_STREAM;
6771

6872
return new Promise((resolve, reject) => {
6973
let accumulatedText = '';
@@ -192,7 +196,7 @@ export async function sendChatMessageSync(request: ChatRequest): Promise<ChatRes
192196
*/
193197
export async function checkChatAgentHealth(): Promise<boolean> {
194198
try {
195-
const response = await fetch(API_ENDPOINT.replace('/api/v1/chat', '/health'));
199+
const response = await fetch(API_PATHS.CHAT_HEALTH);
196200
return response.ok;
197201
} catch {
198202
return false;

0 commit comments

Comments
 (0)