fix: resolve frontend API routing issues for Traefik deployment
Test and Lint / backend-test (push) Successful in 1m16s
continuous-integration/drone/push Build is failing
Test and Lint / frontend-test (push) Successful in 2m18s
Version and Release / version-bump (push) Successful in 43s
Version and Release / trigger-drone (push) Successful in 4s

Major fixes for production deployment with Traefik:

1. API Path Fixes:
   - Remove double /api prefix from all frontend service calls
   - Fix auth.service.ts to use correct paths (/auth/admin/login)
   - Update all services to use single /api prefix from base URL
   - Fix template literal paths in photo services

2. Docker Configuration:
   - Add build args for VITE_API_URL in docker-compose.prod.yml
   - Create Dockerfile.prod with proper API URL configuration
   - Ensure frontend is built with correct API base path

3. Documentation:
   - Add comprehensive TRAEFIK_DEPLOYMENT.md guide
   - Document proper Traefik labels and routing configuration
   - Include troubleshooting steps for common issues
   - Explain network configuration and SSL handling

This resolves:
- 502 Bad Gateway errors
- Double /api/api paths in requests
- Frontend unable to communicate with backend
- Login functionality not working

The frontend now correctly calls the backend API through Traefik's
routing, with all requests going to /api/* being forwarded to the
backend service on port 3000.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-13 23:17:45 +02:00
parent 689861f671
commit ac1cd96ecd
25 changed files with 422 additions and 75 deletions
@@ -15,7 +15,7 @@ export const GlobalThemeProvider: React.FC<GlobalThemeProviderProps> = ({ childr
const { data: settingsData } = useQuery({
queryKey: ['global-theme-settings'],
queryFn: async () => {
const response = await api.get('/api/public/settings');
const response = await api.get('/public/settings');
return response.data;
},
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
+1 -1
View File
@@ -23,7 +23,7 @@ export const MaintenanceMode: React.FC = () => {
queryKey: ['public-settings-maintenance'],
queryFn: async () => {
try {
const response = await api.get('/api/public/settings');
const response = await api.get('/public/settings');
return response.data;
} catch (error) {
// Return empty object if settings can't be fetched
@@ -30,7 +30,7 @@ export const MaintenanceWrapper: React.FC<MaintenanceWrapperProps> = ({ children
queryFn: async () => {
try {
// Make a lightweight request to check maintenance status
await api.get('/api/public/settings');
await api.get('/public/settings');
// If successful, maintenance mode is off
setMaintenanceMode(false);
return { maintenance: false };
@@ -62,7 +62,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
}
try {
const response = await api.post(`/api/admin/events/${eventId}/upload`, formData, {
const response = await api.post(`/admin/events/${eventId}/upload`, formData, {
// Don't set Content-Type header - axios will set it with the boundary
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
@@ -15,7 +15,7 @@ interface SystemVersion {
}
async function fetchSystemVersion(): Promise<SystemVersion> {
const response = await api.get<SystemVersion>('/api/admin/system/version');
const response = await api.get<SystemVersion>('/admin/system/version');
return response.data;
}
@@ -79,7 +79,7 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
const { data: settingsData } = useQuery({
queryKey: ['gallery-settings'],
queryFn: async () => {
const response = await api.get('/api/public/settings');
const response = await api.get('/public/settings');
return response.data;
},
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
@@ -195,8 +195,8 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
if (watermarkEnabled) {
photos = photos.map(photo => ({
...photo,
url: `/api/gallery/${slug}/photo/${photo.id}`,
thumbnail_url: `/api/gallery/${slug}/photo/${photo.id}` // Use watermarked version for thumbnails too
url: `/gallery/${slug}/photo/${photo.id}`,
thumbnail_url: `/gallery/${slug}/photo/${photo.id}` // Use watermarked version for thumbnails too
}));
}
@@ -63,7 +63,7 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
}
try {
await api.post(`/api/gallery/${eventId}/upload`, formData, {
await api.post(`/gallery/${eventId}/upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},