feat: move SaaS app to /platform base path, Logto becomes catch-all
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:
@@ -76,7 +76,8 @@ services:
|
|||||||
start_period: 15s
|
start_period: 15s
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.entrypoints=websecure
|
||||||
- traefik.http.routers.logto.tls=true
|
- traefik.http.routers.logto.tls=true
|
||||||
- traefik.http.services.logto.loadbalancer.server.port=3001
|
- traefik.http.services.logto.loadbalancer.server.port=3001
|
||||||
@@ -142,15 +143,10 @@ services:
|
|||||||
CLICKHOUSE_URL: jdbc:clickhouse://clickhouse:8123/cameleer
|
CLICKHOUSE_URL: jdbc:clickhouse://clickhouse:8123/cameleer
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- traefik.enable=true
|
||||||
- traefik.http.routers.api.rule=PathPrefix(`/api`)
|
- traefik.http.routers.saas.rule=PathPrefix(`/platform`)
|
||||||
- traefik.http.routers.api.entrypoints=websecure
|
- traefik.http.routers.saas.entrypoints=websecure
|
||||||
- traefik.http.routers.api.tls=true
|
- traefik.http.routers.saas.tls=true
|
||||||
- traefik.http.routers.api.service=spa
|
- traefik.http.services.saas.loadbalancer.server.port=8080
|
||||||
- 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
|
|
||||||
networks:
|
networks:
|
||||||
- cameleer
|
- cameleer
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ SERVER_UI_PASS="${SERVER_UI_PASS:-admin}"
|
|||||||
# Redirect URIs (derived from PUBLIC_HOST and PUBLIC_PROTOCOL)
|
# Redirect URIs (derived from PUBLIC_HOST and PUBLIC_PROTOCOL)
|
||||||
HOST="${PUBLIC_HOST:-localhost}"
|
HOST="${PUBLIC_HOST:-localhost}"
|
||||||
PROTO="${PUBLIC_PROTOCOL:-https}"
|
PROTO="${PUBLIC_PROTOCOL:-https}"
|
||||||
SPA_REDIRECT_URIS="[\"${PROTO}://${HOST}/callback\"]"
|
SPA_REDIRECT_URIS="[\"${PROTO}://${HOST}/platform/callback\"]"
|
||||||
SPA_POST_LOGOUT_URIS="[\"${PROTO}://${HOST}/login\"]"
|
SPA_POST_LOGOUT_URIS="[\"${PROTO}://${HOST}/platform/login\"]"
|
||||||
TRAD_REDIRECT_URIS="[\"http://${HOST}:8081/oidc/callback\"]"
|
TRAD_REDIRECT_URIS="[\"http://${HOST}:8081/oidc/callback\"]"
|
||||||
TRAD_POST_LOGOUT_URIS="[\"http://${HOST}:8081\"]"
|
TRAD_POST_LOGOUT_URIS="[\"http://${HOST}:8081\"]"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
server:
|
||||||
|
servlet:
|
||||||
|
context-path: /platform
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
jpa:
|
jpa:
|
||||||
show-sql: false
|
show-sql: false
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
server:
|
||||||
|
servlet:
|
||||||
|
context-path: /platform
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: cameleer-saas
|
name: cameleer-saas
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const API_BASE = '/api';
|
const API_BASE = '/platform/api';
|
||||||
|
|
||||||
let tokenProvider: (() => Promise<string | undefined>) | null = null;
|
let tokenProvider: (() => Promise<string | undefined>) | null = null;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function fetchConfig(): Promise<AppConfig> {
|
|||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/config');
|
const response = await fetch('/platform/api/config');
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
cached = await response.json();
|
cached = await response.json();
|
||||||
return cached!;
|
return cached!;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ function App() {
|
|||||||
>
|
>
|
||||||
<TokenSync resource={config.logtoResource} />
|
<TokenSync resource={config.logtoResource} />
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<BrowserRouter>
|
<BrowserRouter basename="/platform">
|
||||||
<AppRouter />
|
<AppRouter />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
base: '/platform/',
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user