test_api: assert /health returns plain text ok instead of JSON parse.
auth: RefreshRequest.refresh_token optional so SPA POST {} is not 422.
prune: allow leading underscore in asset names to avoid deleting _plugin-vue_export-helper.
Add run_test_api_on_server.sh and deployment follow-up changelog.
Co-authored-by: Cursor <cursoragent@cursor.com>
Bing wallpaper endpoint (/bing-wallpapers) was returning 404 from HTTP
because FastAPI matched it against the /{key} catch-all route at position
2 before the specific route at position 13 ever got reached.
- Moved wallpaper routes (bing-wallpapers, bing-wallpaper) and helper code
before the /{key} wildcard route
- Removed dead guard code in get_setting() that was never effective —
FastAPI route matching happens before the handler body executes
- Removed duplicate wallpaper code block at end of file
Root cause: FastAPI matches routes in registration order. /{key} at
position 2 matched 'bing-wallpapers' as the key parameter, returning
'Setting not found' instead of routing to the wallpaper endpoint.
FastAPI matches routes in order: /{key} registered before bing-wallpapers
because routes are sorted by path. /{key} matches 'bing-wallpapers' as a
key name, returning 404 'Setting not found' instead of hitting the actual
bing_wallpapers handler.
Fixed by adding a guard in get_setting() to skip these fixed path names,
and crucially by ensuring bing-wallpaper(s) routes are registered BEFORE
the /{key} catch-all in the router.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Frontend: fullscreen wallpaper background with 1.5s crossfade transition,
login card centered with glass effect, images rotate every hour
- Backend: new /api/settings/bing-wallpapers endpoint fetches 8 recent images
from Bing HPImageArchive, caches to web/app/wallpapers/, returns all URLs
- Auto-cleanup: removes files older than 7 days, keeps max 12 newest
- Old /bing-wallpaper endpoint kept for backward compatibility
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Path(__file__) is server/api/settings.py, so:
.parent → api/ .parent → server/ .parent → Nexus/ (ROOT)
.parent → (above ROOT — wrong!)
- Changed from .parent.parent.parent to .parent.parent.parent.parent
to reach the project root, then into web/app/wallpapers/
- Moved _WALLPAPER_DIR.mkdir into the async function body
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added /app/wallpapers/ to _APP_PUBLIC_PREFIXES so cached wallpaper images
are served without requiring login auth
- Wallpaper files are now saved to web/app/wallpapers/ by bing_wallpaper() endpoint
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Changed bing-wallpaper endpoint from URL proxy to image downloader
- Saves wallpaper to web/app/wallpapers/YYYY-MM-DD.jpg
- Auto-deletes wallpapers older than 7 days on each request
- Falls back to yesterday's cached file if download fails
- Added Path import for filesystem access
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added GET /api/settings/bing-wallpaper — proxies cn.bing.com HPImageArchive
to avoid CORS issues, returns {url} for the daily wallpaper
- Added /api/settings/bing-wallpaper to PUBLIC_PREFIXES in auth_jwt.py
so the login page can fetch it without authentication
- Login page now fetches wallpaper via backend proxy instead of direct CORS-blocked fetch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The install wizard wrote '--host 0.0.0.0' which exposed the raw uvicorn
port 8600 on the public IP, bypassing Nginx HTTPS/TLS/WAF/middleware.
Changed to 127.0.0.1 — only local Nginx can reach the backend.
Also applied to running server via supervisor config fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Vuetify SPA is now the sole frontend entry point at /app/.
Old pages (alerts/servers/scripts/...html) replaced by Vue router.
Keep install.html for setup wizard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Old Tailwind HTML pages removed from server — Vuetify SPA is now
the sole entry at /app/. Only install.html remains for setup wizard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The new Vuetify SPA uses hash routing — all pages served from single
index.html. The old middleware only whitelisted individual HTML page
paths (login.html etc.), blocking the SPA entry point with 404.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>