feat: move SaaS app to /platform base path, Logto becomes catch-all
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 41s

Eliminates all Logto path enumeration in Traefik. Routing is now:
- /platform/* → cameleer-saas (SPA + API)
- /server/* → server-ui
- /* (catch-all) → Logto (sign-in, OIDC, assets, everything)

Spring context-path handles backend prefix transparently. No changes
needed in controllers, SecurityConfig, or interceptors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-05 23:06:41 +02:00
parent 4ab72425ae
commit 4997f7a6a9
8 changed files with 20 additions and 15 deletions

View File

@@ -76,7 +76,8 @@ services:
start_period: 15s
labels:
- traefik.enable=true
- traefik.http.routers.logto.rule=PathPrefix(`/oidc`) || PathPrefix(`/interaction`) || PathPrefix(`/assets`) || PathPrefix(`/sign-in`) || PathPrefix(`/register`) || PathPrefix(`/consent`) || PathPrefix(`/single-sign-on`) || PathPrefix(`/social`) || PathPrefix(`/unknown-session`) || PathPrefix(`/api/interaction`) || PathPrefix(`/api/experience`) || PathPrefix(`/api/.well-known`)
- traefik.http.routers.logto.rule=PathPrefix(`/`)
- traefik.http.routers.logto.priority=1
- traefik.http.routers.logto.entrypoints=websecure
- traefik.http.routers.logto.tls=true
- traefik.http.services.logto.loadbalancer.server.port=3001
@@ -142,15 +143,10 @@ services:
CLICKHOUSE_URL: jdbc:clickhouse://clickhouse:8123/cameleer
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=PathPrefix(`/api`)
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.tls=true
- traefik.http.routers.api.service=spa
- traefik.http.routers.spa.rule=PathPrefix(`/`)
- traefik.http.routers.spa.priority=1
- traefik.http.routers.spa.entrypoints=websecure
- traefik.http.routers.spa.tls=true
- traefik.http.services.spa.loadbalancer.server.port=8080
- traefik.http.routers.saas.rule=PathPrefix(`/platform`)
- traefik.http.routers.saas.entrypoints=websecure
- traefik.http.routers.saas.tls=true
- traefik.http.services.saas.loadbalancer.server.port=8080
networks:
- cameleer

View File

@@ -43,8 +43,8 @@ SERVER_UI_PASS="${SERVER_UI_PASS:-admin}"
# Redirect URIs (derived from PUBLIC_HOST and PUBLIC_PROTOCOL)
HOST="${PUBLIC_HOST:-localhost}"
PROTO="${PUBLIC_PROTOCOL:-https}"
SPA_REDIRECT_URIS="[\"${PROTO}://${HOST}/callback\"]"
SPA_POST_LOGOUT_URIS="[\"${PROTO}://${HOST}/login\"]"
SPA_REDIRECT_URIS="[\"${PROTO}://${HOST}/platform/callback\"]"
SPA_POST_LOGOUT_URIS="[\"${PROTO}://${HOST}/platform/login\"]"
TRAD_REDIRECT_URIS="[\"http://${HOST}:8081/oidc/callback\"]"
TRAD_POST_LOGOUT_URIS="[\"http://${HOST}:8081\"]"

View File

@@ -1,3 +1,7 @@
server:
servlet:
context-path: /platform
spring:
jpa:
show-sql: false

View File

@@ -1,3 +1,7 @@
server:
servlet:
context-path: /platform
spring:
application:
name: cameleer-saas

View File

@@ -1,4 +1,4 @@
const API_BASE = '/api';
const API_BASE = '/platform/api';
let tokenProvider: (() => Promise<string | undefined>) | null = null;

View File

@@ -11,7 +11,7 @@ export async function fetchConfig(): Promise<AppConfig> {
if (cached) return cached;
try {
const response = await fetch('/api/config');
const response = await fetch('/platform/api/config');
if (response.ok) {
cached = await response.json();
return cached!;

View File

@@ -80,7 +80,7 @@ function App() {
>
<TokenSync resource={config.logtoResource} />
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<BrowserRouter basename="/platform">
<AppRouter />
</BrowserRouter>
</QueryClientProvider>

View File

@@ -12,6 +12,7 @@ export default defineConfig({
},
},
},
base: '/platform/',
build: {
outDir: 'dist',
emptyOutDir: true,