diff --git a/app.py b/app.py index 6eff416..86b8df9 100644 --- a/app.py +++ b/app.py @@ -32,7 +32,13 @@ FRONTEND_DIR = os.path.join(os.path.dirname(__file__), "..", "frontend") # live at https:///thermograph/ behind a shared domain. Override with the # THERMOGRAPH_BASE env var. The frontend uses base-relative URLs, so it follows # this automatically without hardcoding the prefix. -BASE = "/" + os.environ.get("THERMOGRAPH_BASE", "/thermograph").strip("/") +# +# THERMOGRAPH_BASE=/ (or empty) means the app owns the whole domain: BASE becomes +# "" so every route sits at the domain root ("/", "/calendar", "/api/v2/…") with +# no prefix and no leading double slash. A non-empty value keeps the sub-path form +# ("/thermograph"). +_BASE = os.environ.get("THERMOGRAPH_BASE", "/thermograph").strip("/") +BASE = f"/{_BASE}" if _BASE else "" def _weather_fetch_error(e) -> HTTPException: @@ -592,10 +598,13 @@ def _page(name): # The un-slashed base redirects to BASE/ so the frontend's relative asset URLs -# resolve correctly. The app stays scoped to BASE and never claims "/", leaving -# the domain root free for another app (e.g. a portfolio) to own via the proxy. +# resolve correctly. Under a sub-path this keeps the app scoped to BASE (never +# claiming "/", so the domain root stays free for another app via the proxy). When +# BASE is "" the app owns the root: "/" is already the index route below, so there +# is no bare base to redirect (and "" is not a valid route path). # Pages also answer HEAD — link-preview crawlers probe with it before fetching. -app.add_api_route(BASE, lambda: RedirectResponse(url=f"{BASE}/"), methods=["GET", "HEAD"], include_in_schema=False) +if BASE: + app.add_api_route(BASE, lambda: RedirectResponse(url=f"{BASE}/"), methods=["GET", "HEAD"], include_in_schema=False) app.add_api_route(f"{BASE}/", _page("index.html"), methods=["GET", "HEAD"], include_in_schema=False) app.add_api_route(f"{BASE}/calendar", _page("calendar.html"), methods=["GET", "HEAD"], include_in_schema=False) app.add_api_route(f"{BASE}/day", _page("day.html"), methods=["GET", "HEAD"], include_in_schema=False) @@ -604,5 +613,7 @@ app.add_api_route(f"{BASE}/legend", _page("legend.html"), methods=["GET", "HEAD" app.add_api_route(f"{BASE}/alerts", _page("subscriptions.html"), methods=["GET", "HEAD"], include_in_schema=False) # Everything else under BASE (app.js, style.css, nav.js, …) is a static asset. -# Registered last so the explicit page routes above win. -app.mount(BASE, StaticFiles(directory=FRONTEND_DIR), name="static") +# Registered last so the explicit page routes above win. Mounts must start with +# "/", so at the root (BASE == "") mount at "/" — the earlier routes still win +# because Starlette matches in registration order. +app.mount(BASE or "/", StaticFiles(directory=FRONTEND_DIR), name="static")