diff --git a/backend/app/config.py b/backend/app/config.py
index fcd8d3e..df42064 100644
--- a/backend/app/config.py
+++ b/backend/app/config.py
@@ -18,6 +18,9 @@ class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
app_mode: AppMode = AppMode.DEMO
+ # Optional public URL of a fixture-replay twin of this deployment; the UI
+ # offers it as an escape hatch when the live Spotify quota runs out.
+ demo_instance_url: str = ""
# Spotify application and OAuth. The redirect URI must exactly match a
# URI registered in the Spotify developer dashboard, port included.
diff --git a/backend/app/main.py b/backend/app/main.py
index 4bd51cf..82d9982 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -124,7 +124,10 @@ def create_app(
@app.get("/api/health")
def health() -> dict[str, str]:
- return {"status": "ok", "mode": active_settings.app_mode}
+ payload = {"status": "ok", "mode": active_settings.app_mode}
+ if active_settings.demo_instance_url:
+ payload["demo_url"] = active_settings.demo_instance_url
+ return payload
app.include_router(router)
app.include_router(recommendations_router)
diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue
index 786f1ff..09dfd7e 100644
--- a/frontend/src/components/AppHeader.vue
+++ b/frontend/src/components/AppHeader.vue
@@ -8,6 +8,7 @@ const props = defineProps<{
auth: AuthState
mode: AppMode | null
healthFailed: boolean
+ demoUrl: string | null
}>()
const emit = defineEmits<{ logout: []; reset: []; toggleDev: [opener: HTMLElement] }>()
@@ -47,6 +48,9 @@ const modeLabel = computed(() => {
{{ modeLabel }}
+
+ {{ messages.appHeaderDemoInstance }}
+