feat: Migrate to MySQL and add unified environment configuration

## Database Migration (SQLite → MySQL)
- Add Alembic migration framework
- Add 'tr_' prefix to all tables to avoid conflicts in shared database
- Remove SQLite support, use MySQL exclusively
- Add pymysql driver dependency
- Change ad_token column to Text type for long JWT tokens

## Unified Environment Configuration
- Centralize all hardcoded settings to environment variables
- Backend: Extend Settings class in app/core/config.py
- Frontend: Use Vite environment variables (import.meta.env)
- Docker: Move credentials to environment variables
- Update .env.example files with comprehensive documentation

## Test Organization
- Move root-level test files to tests/ directory:
  - test_chat_room.py → tests/test_chat_room.py
  - test_websocket.py → tests/test_websocket.py
  - test_realtime_implementation.py → tests/test_realtime_implementation.py
- Fix path references in test_realtime_implementation.py

Breaking Changes:
- CORS now requires explicit origins (no more wildcard)
- All database tables renamed with 'tr_' prefix
- SQLite no longer supported

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-07 14:15:11 +08:00
parent 1d5d4d447d
commit 92834dbe0e
39 changed files with 1558 additions and 136 deletions

View File

@@ -61,12 +61,18 @@ export function useCreateMessage(roomId: string) {
})
}
// Configurable refetch interval for online users (default 30 seconds)
const MESSAGES_REFETCH_INTERVAL = parseInt(
import.meta.env.VITE_MESSAGES_REFETCH_INTERVAL_MS || '30000',
10
)
export function useOnlineUsers(roomId: string) {
return useQuery({
queryKey: messageKeys.online(roomId),
queryFn: () => messagesService.getOnlineUsers(roomId),
enabled: !!roomId,
refetchInterval: 30000, // Refresh every 30 seconds
refetchInterval: MESSAGES_REFETCH_INTERVAL,
})
}

View File

@@ -14,6 +14,12 @@ const reportKeys = {
[...reportKeys.all, 'detail', roomId, reportId] as const,
}
// Configurable stale time for reports (default 30 seconds)
const REPORTS_STALE_TIME = parseInt(
import.meta.env.VITE_REPORTS_STALE_TIME_MS || '30000',
10
)
/**
* Hook to list reports for a room
*/
@@ -22,7 +28,7 @@ export function useReports(roomId: string) {
queryKey: reportKeys.list(roomId),
queryFn: () => reportsService.listReports(roomId),
enabled: !!roomId,
staleTime: 30000, // 30 seconds
staleTime: REPORTS_STALE_TIME,
})
}

View File

@@ -12,7 +12,10 @@ import type {
} from '../types'
const RECONNECT_DELAY = 1000
const MAX_RECONNECT_DELAY = 30000
const MAX_RECONNECT_DELAY = parseInt(
import.meta.env.VITE_MAX_RECONNECT_DELAY_MS || '30000',
10
)
const RECONNECT_MULTIPLIER = 2
interface UseWebSocketOptions {

View File

@@ -3,10 +3,13 @@ import axios, { type AxiosError, type InternalAxiosRequestConfig } from 'axios'
// API Base URL: use environment variable or default to relative path
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api'
// API Timeout: configurable via environment variable (default 30 seconds)
const API_TIMEOUT = parseInt(import.meta.env.VITE_API_TIMEOUT_MS || '30000', 10)
// Create axios instance
const api = axios.create({
baseURL: API_BASE_URL,
timeout: 30000,
timeout: API_TIMEOUT,
headers: {
'Content-Type': 'application/json',
},