Files
csgowtf/docs/CORS_PROXY.md
vikingowl 8f3b652740 feat: Implement Phase 1 critical features and fix API integration
This commit completes the first phase of feature parity implementation and
resolves all API integration issues to match the backend API format.

## API Integration Fixes

- Remove all hardcoded default values from transformers (tick_rate, kast, player_count, steam_updated)
- Update TypeScript types to make fields optional where backend doesn't guarantee them
- Update Zod schemas to validate optional fields correctly
- Fix mock data to match real API response format (plain arrays, not wrapped objects)
- Update UI components to handle undefined values with proper fallbacks
- Add comprehensive API documentation for Match and Player endpoints

## Phase 1 Features Implemented (3/6)

### 1. Player Tracking System 
- Created TrackPlayerModal.svelte with auth code input
- Integrated track/untrack player API endpoints
- Added UI for providing optional share code
- Displays tracked status on player profiles
- Full validation and error handling

### 2. Share Code Parsing 
- Created ShareCodeInput.svelte component
- Added to matches page for easy match submission
- Real-time validation of share code format
- Parse status feedback with loading states
- Auto-redirect to match page on success

### 3. VAC/Game Ban Status 
- Added VAC and game ban count/date fields to Player type
- Display status badges on player profile pages
- Show ban count and date when available
- Visual indicators using DaisyUI badge components

## Component Improvements

- Modal.svelte: Added Svelte 5 Snippet types, actions slot support
- ThemeToggle.svelte: Removed deprecated svelte:component usage
- Tooltip.svelte: Fixed type safety with Snippet type
- All new components follow Svelte 5 runes pattern ($state, $derived, $bindable)

## Type Safety & Linting

- Fixed all ESLint errors (any types → proper types)
- Fixed form label accessibility issues
- Replaced error: any with error: unknown + proper type guards
- Added Snippet type imports where needed
- Updated all catch blocks to use instanceof Error checks

## Static Assets

- Migrated all files from public/ to static/ directory per SvelteKit best practices
- Moved 200+ map icons, screenshots, and other assets
- Updated all import paths to use /images/ (served from static/)

## Documentation

- Created IMPLEMENTATION_STATUS.md tracking all 15 missing features
- Updated API.md with optional field annotations
- Created MATCHES_API.md with comprehensive endpoint documentation
- Added inline comments marking optional vs required fields

## Testing

- Updated mock fixtures to remove default values
- Fixed mock handlers to return plain arrays like real API
- Ensured all components handle undefined gracefully

## Remaining Phase 1 Tasks

- [ ] Add VAC status column to match scoreboard
- [ ] Create weapons statistics tab for matches
- [ ] Implement recently visited players on home page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 19:31:18 +01:00

394 lines
8.7 KiB
Markdown

# API Proxying with SvelteKit Server Routes
This document explains how API requests are proxied to the backend using SvelteKit server routes.
## Why Use Server Routes?
The CS2.WTF frontend uses **SvelteKit server routes** to proxy API requests to the backend. This approach provides several benefits:
-**Works in all environments**: Development, preview, and production
-**No CORS issues**: Requests are server-side
-**Single code path**: Same behavior everywhere
-**Flexible backend switching**: Change one environment variable
-**Future-proof**: Can add caching, rate limiting, auth later
-**Better security**: Backend URL not exposed to client
## Architecture
### Request Flow
```
Browser → /api/matches → SvelteKit Server Route → Backend → Response
```
**Detailed Flow**:
```
1. Browser: GET http://localhost:5173/api/matches?limit=20
2. SvelteKit: Routes to src/routes/api/[...path]/+server.ts
3. Server Handler: Reads VITE_API_BASE_URL environment variable
4. Backend Call: GET https://api.csgow.tf/matches?limit=20
5. Backend: Returns JSON response
6. Server Handler: Forwards response to browser
7. Browser: Receives response (no CORS issues!)
```
**SSR (Server-Side Rendering) Flow**:
```
1. Page Load: +page.ts calls api.matches.getMatches()
2. API Client: Detects import.meta.env.SSR === true
3. Direct Call: GET https://api.csgow.tf/matches?limit=20
4. Backend: Returns JSON response
5. SSR: Renders page with data
```
**Note**: SSR bypasses the SvelteKit route and calls the backend directly because relative URLs (`/api`) don't work during server-side rendering.
### Key Components
**1. SvelteKit Server Route** (`src/routes/api/[...path]/+server.ts`)
- Catch-all route that matches `/api/*`
- Forwards requests to backend
- Supports GET, POST, DELETE methods
- Handles errors gracefully
**2. API Client** (`src/lib/api/client.ts`)
- Browser: Uses `/api` base URL (routes to SvelteKit)
- SSR: Uses `VITE_API_BASE_URL` directly (bypasses SvelteKit route)
- Automatically detects environment with `import.meta.env.SSR`
**3. Environment Variable** (`.env`)
- `VITE_API_BASE_URL` controls which backend to use
- Switch between local and production easily
## Configuration
### Environment Variables
**`.env`**:
```env
# Production API (default)
VITE_API_BASE_URL=https://api.csgow.tf
# Local backend (for development)
# VITE_API_BASE_URL=http://localhost:8000
```
**Switching Backends**:
```bash
# Use production API
echo "VITE_API_BASE_URL=https://api.csgow.tf" > .env
npm run dev
# Use local backend
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
npm run dev
```
### Server Route Implementation
**File**: `src/routes/api/[...path]/+server.ts`
```typescript
import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.csgow.tf';
export const GET: RequestHandler = async ({ params, url }) => {
const path = params.path; // e.g., "matches"
const queryString = url.search; // e.g., "?limit=20"
const backendUrl = `${API_BASE_URL}/${path}${queryString}`;
try {
const response = await fetch(backendUrl);
const data = await response.json();
return json(data);
} catch (err) {
throw error(503, 'Unable to connect to backend');
}
};
```
### API Client Configuration
**File**: `src/lib/api/client.ts`
```typescript
// Simple, single configuration
const API_BASE_URL = '/api';
// Always routes to SvelteKit server routes
// No environment detection needed
```
## Testing the Setup
### 1. Check Environment Variable
```bash
cat .env
# Should show:
VITE_API_BASE_URL=https://api.csgow.tf
# or
VITE_API_BASE_URL=http://localhost:8000
```
### 2. Start Development Server
```bash
npm run dev
# Server starts on http://localhost:5173
```
### 3. Check Network Requests
Open DevTools → Network tab:
- ✅ Requests go to `/api/matches`, `/api/player/123`, etc.
- ✅ Status should be `200 OK`
- ✅ No CORS errors in console
### 4. Test Both Backends
**Test Production API**:
```bash
# Set production API
echo "VITE_API_BASE_URL=https://api.csgow.tf" > .env
# Start dev server
npm run dev
# Visit http://localhost:5173/matches
# Should load matches from production API
```
**Test Local Backend**:
```bash
# Start local backend first
cd ../csgowtfd
go run main.go
# In another terminal, set local API
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
# Start dev server
npm run dev
# Visit http://localhost:5173/matches
# Should load matches from local backend
```
## Common Issues
### Issue 1: 503 Service Unavailable
**Symptom**: API requests return 503 error
**Possible Causes**:
1. Backend is not running
2. Wrong `VITE_API_BASE_URL` in `.env`
3. Network connectivity issues
**Fix**:
```bash
# Check .env file
cat .env
# If using local backend, make sure it's running
curl http://localhost:8000/matches
# If using production API, check connectivity
curl https://api.csgow.tf/matches
# Restart dev server after changing .env
npm run dev
```
### Issue 2: 404 Not Found
**Symptom**: `/api/*` routes return 404
**Cause**: SvelteKit server route file missing or not loaded
**Fix**:
```bash
# Check file exists
ls src/routes/api/[...path]/+server.ts
# If missing, create it
mkdir -p src/routes/api/'[...path]'
# Then create +server.ts file
# Restart dev server
npm run dev
```
### Issue 3: Environment Variable Not Loading
**Symptom**: Server route uses wrong backend URL
**Cause**: Changes to `.env` require server restart
**Fix**:
```bash
# Stop dev server (Ctrl+C)
# Update .env
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
# Start dev server again
npm run dev
```
### Issue 4: CORS Errors Still Appearing
**Symptom**: Browser console shows CORS errors
**Cause**: API client is not using `/api` prefix
**Fix**:
Check `src/lib/api/client.ts`:
```typescript
// Should be:
const API_BASE_URL = '/api';
// Not:
const API_BASE_URL = 'https://api.csgow.tf'; // ❌ Wrong
```
## How It Works Compared to Vite Proxy
### Old Approach (Vite Proxy)
```
Development:
Browser → /api → Vite Proxy → Backend
Production:
Browser → Backend (direct, different code path)
```
**Problems**:
- Two different code paths (dev vs prod)
- Proxy only works in development
- SSR has to bypass proxy
- Complex configuration
### New Approach (SvelteKit Server Routes)
```
All Environments:
Browser → /api → SvelteKit Route → Backend
```
**Benefits**:
- Single code path
- Works in dev, preview, and production
- Consistent behavior everywhere
- Simpler configuration
## Adding Features
### Add Request Caching
**File**: `src/routes/api/[...path]/+server.ts`
```typescript
const cache = new Map<string, { data: any; expires: number }>();
export const GET: RequestHandler = async ({ params, url }) => {
const cacheKey = `${params.path}${url.search}`;
// Check cache
const cached = cache.get(cacheKey);
if (cached && Date.now() < cached.expires) {
return json(cached.data);
}
// Fetch from backend
const data = await fetch(`${API_BASE_URL}/${params.path}${url.search}`).then((r) => r.json());
// Cache for 5 minutes
cache.set(cacheKey, {
data,
expires: Date.now() + 5 * 60 * 1000
});
return json(data);
};
```
### Add Rate Limiting
```typescript
import { rateLimit } from '$lib/server/rateLimit';
export const GET: RequestHandler = async ({ request, params, url }) => {
// Check rate limit
await rateLimit(request);
// Continue with normal flow...
};
```
### Add Authentication
```typescript
export const GET: RequestHandler = async ({ request, params, url }) => {
// Get auth token from cookie
const token = request.headers.get('cookie')?.includes('auth_token');
// Forward to backend with auth
const response = await fetch(backendUrl, {
headers: {
Authorization: `Bearer ${token}`
}
});
// ...
};
```
## Summary
| Feature | Vite Proxy | SvelteKit Routes |
| --------------------- | ---------- | ---------------- |
| Works in dev | ✅ | ✅ |
| Works in production | ❌ | ✅ |
| Single code path | ❌ | ✅ |
| Can add caching | ❌ | ✅ |
| Can add rate limiting | ❌ | ✅ |
| Can add auth | ❌ | ✅ |
| SSR compatible | ❌ | ✅ |
**SvelteKit server routes provide a production-ready, maintainable solution for API proxying that works in all environments.**