mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-05 11:12:56 +00:00
@@ -62,10 +62,10 @@ MAX_FILES=5 # Maximum number of files per upload
|
||||
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8080
|
||||
# Frontend Configuration
|
||||
REACT_APP_NAME=Fotbal Club Manager
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_API_URL=/api/v1
|
||||
|
||||
# FACR API Configuration
|
||||
REACT_APP_FACR_API_BASE_URL=http://localhost:8080/api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=/api/v1/facr
|
||||
REACT_APP_FACR_API_TIMEOUT=5000
|
||||
REACT_APP_FACR_CACHE_TTL=3600000
|
||||
|
||||
|
||||
+2
-2
@@ -62,10 +62,10 @@ MAX_FILES=5 # Maximum number of files per upload
|
||||
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8080
|
||||
# Frontend Configuration
|
||||
REACT_APP_NAME=Fotbal Club Manager
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_API_URL=/api/v1
|
||||
|
||||
# FACR API Configuration
|
||||
REACT_APP_FACR_API_BASE_URL=http://localhost:8080/api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=/api/v1/facr
|
||||
REACT_APP_FACR_API_TIMEOUT=5000
|
||||
REACT_APP_FACR_CACHE_TTL=3600000
|
||||
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"items":[],"page":1,"page_size":10,"total":0}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"lastUpdated":"2025-10-24T14:27:54Z"}
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"baseURL": "http://127.0.0.1:8080/api/v1",
|
||||
"duration_ms": 15,
|
||||
"endpoints": [
|
||||
{
|
||||
"path": "/settings",
|
||||
"file": "settings.json",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"path": "/articles?page=1\u0026page_size=10\u0026published=true",
|
||||
"file": "articles.json",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"path": "/sponsors",
|
||||
"file": "sponsors.json",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"path": "/events/upcoming",
|
||||
"file": "events_upcoming.json",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"path": "/public/team-logo-overrides",
|
||||
"file": "team_logo_overrides.json",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"path": "/competition-aliases",
|
||||
"file": "competition_aliases.json",
|
||||
"ok": true
|
||||
}
|
||||
],
|
||||
"lastUpdated": "2025-10-24T14:27:54Z"
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"about_html":"","accent_color":"#e53e3e","background_color":"#ffffff","club_id":"","club_logo_url":"","club_name":"","club_type":"","club_url":"","contact_address":"","contact_city":"","contact_country":"","contact_email":"","contact_phone":"","contact_zip":"","custom_nav":null,"facebook_url":"","font_body":"Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif","font_heading":"Poppins, sans-serif","gallery_label":"","gallery_url":"","instagram_url":"","location_latitude":0,"location_longitude":0,"map_style":"","map_zoom_level":0,"merch_items":null,"merch_limit":0,"merch_module_enabled":false,"merch_source":"","merch_style":"","primary_color":"#1a365d","secondary_color":"#2b6cb0","show_about_in_nav":false,"show_map_on_homepage":false,"sponsors_layout":"","sponsors_theme":"","text_color":"#1a202c","videos":null,"videos_items":null,"videos_limit":6,"videos_module_enabled":false,"videos_source":"auto","videos_style":"slider","youtube_url":""}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"by_name":{}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"etag":"","fetched_at":"2025-10-24T14:27:54Z","last_modified":""}
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_API_URL=/api/v1
|
||||
REACT_APP_NAME=Fotbal Club Manager
|
||||
REACT_APP_ENV=development
|
||||
|
||||
# FACR API Configuration - Local instance
|
||||
# Backend exposes the FACR proxy under /api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=http://localhost:8080/api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=/api/v1/facr
|
||||
REACT_APP_FACR_API_TIMEOUT=5000 # 5 seconds
|
||||
REACT_APP_FACR_CACHE_TTL=3600000 # 1 hour in milliseconds
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_API_URL=/api/v1
|
||||
# Alternatively, you can set only the backend origin and the app will auto-append /api/v1
|
||||
# REACT_APP_API_BASE_URL=http://localhost:8080
|
||||
# REACT_APP_API_BASE_URL=https://api.example.com
|
||||
# Optional: force assets (uploads, dist) to a specific domain (e.g., files.tdvorak.dev)
|
||||
# REACT_APP_ASSET_BASE_URL=https://files.example.com
|
||||
REACT_APP_NAME=Fotbal Club Manager
|
||||
REACT_APP_ENV=development
|
||||
|
||||
# FACR API Configuration - Local instance
|
||||
# Backend exposes the FACR proxy under /api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=http://localhost:8080/api/v1/facr
|
||||
REACT_APP_FACR_API_BASE_URL=/api/v1/facr
|
||||
REACT_APP_FACR_API_TIMEOUT=5000 # 5 seconds
|
||||
REACT_APP_FACR_CACHE_TTL=3600000 # 1 hour in milliseconds
|
||||
|
||||
|
||||
@@ -86,6 +86,38 @@ server {
|
||||
proxy_busy_buffers_size 8k;
|
||||
}
|
||||
|
||||
# Proxy backend-served assets so the frontend can use relative URLs
|
||||
location /uploads/ {
|
||||
proxy_pass http://backend: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;
|
||||
# Allow long cache; backend may set ETag/Last-Modified
|
||||
add_header Cache-Control "public, max-age=2592000";
|
||||
}
|
||||
|
||||
location /dist/ {
|
||||
proxy_pass http://backend: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;
|
||||
add_header Cache-Control "public, max-age=2592000";
|
||||
}
|
||||
|
||||
location /cache/ {
|
||||
proxy_pass http://backend: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;
|
||||
add_header Cache-Control "public, max-age=600";
|
||||
}
|
||||
|
||||
# Error pages
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
|
||||
@@ -4,15 +4,17 @@ import { getToken } from '../utils/auth';
|
||||
// Resolve API URL. Some code uses REACT_APP_API_URL (full api path including /api/v1),
|
||||
// others set REACT_APP_API_BASE_URL (backend origin). Normalize so baseURL always points to API root.
|
||||
const envApiUrl = process.env.REACT_APP_API_URL || process.env.REACT_APP_API_BASE_URL;
|
||||
let API_URL = envApiUrl || 'http://localhost:8080/api/v1';
|
||||
let API_URL = envApiUrl || '/api/v1';
|
||||
|
||||
// If the provided base looks like a backend origin (no /api/), append /api/v1
|
||||
try {
|
||||
const maybe = new URL(API_URL);
|
||||
const maybe = new URL(API_URL, typeof window !== 'undefined' ? window.location.origin : undefined);
|
||||
if (!/\/api\//.test(maybe.pathname)) {
|
||||
// ensure single trailing slash then append api/v1
|
||||
maybe.pathname = maybe.pathname.replace(/\/$/, '') + '/api/v1';
|
||||
API_URL = maybe.toString();
|
||||
} else {
|
||||
API_URL = maybe.toString();
|
||||
}
|
||||
} catch {
|
||||
// If URL parsing fails, keep API_URL as-is
|
||||
|
||||
@@ -8,14 +8,26 @@ export function assetUrl(pathOrUrl?: string | null): string | undefined {
|
||||
if (/^(?:https?:)?\/\//i.test(pathOrUrl) || /^data:/i.test(pathOrUrl)) {
|
||||
return pathOrUrl;
|
||||
}
|
||||
// Rewrite known backend-served asset paths (/uploads, /dist)
|
||||
// Known backend-served asset paths (/uploads, optionally /dist)
|
||||
if (pathOrUrl.startsWith('/uploads') || pathOrUrl.startsWith('/dist')) {
|
||||
const base = process.env.REACT_APP_API_BASE_URL || process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
|
||||
// We want the backend origin, not the API path. Construct from the base.
|
||||
const baseUrl = new URL(base);
|
||||
// 1) Explicit override wins
|
||||
const explicit = process.env.REACT_APP_ASSET_BASE_URL || process.env.REACT_APP_API_BASE_URL || process.env.REACT_APP_API_URL || '';
|
||||
if (explicit) {
|
||||
const baseUrl = new URL(explicit, typeof window !== 'undefined' ? window.location.origin : undefined);
|
||||
baseUrl.pathname = '/';
|
||||
return new URL(pathOrUrl, baseUrl).toString();
|
||||
}
|
||||
// 2) Local dev/IP: talk to backend:8080 directly
|
||||
if (typeof window !== 'undefined') {
|
||||
const { protocol, hostname } = window.location;
|
||||
const isLocal = hostname === 'localhost' || /^\d{1,3}(\.\d{1,3}){3}$/.test(hostname);
|
||||
if (isLocal) {
|
||||
return `${protocol}//${hostname}:8080${pathOrUrl}`;
|
||||
}
|
||||
}
|
||||
// 3) Production/domain: keep relative so frontend Nginx/Cloudflared path proxy forwards to backend
|
||||
return pathOrUrl;
|
||||
}
|
||||
// Otherwise return as-is (relative or other paths)
|
||||
return pathOrUrl;
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user