The nginx sub_filter rewrite couldn't touch the SPA's runtime-built asset
URLs, so the iframed IndeeHub rendered with broken links and images. The
real site refuses iframing (X-Frame-Options), so the demo now opens
https://indee.tx1138.com/ directly via the demo-external mechanism, whose
isDemoExternal() check was previously hardcoded off.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SplashScreen no longer re-checks neode_intro_seen itself: it silently
skipped the whole logo-tap/typing sequence for any browser that had
seen the intro before, even when App.vue explicitly requested it (demo
fresh visits, Replay Intro). App.vue is the single decision point.
- Intro video re-encoded 12.7MB/12.6Mbps → 4.3MB/4.2Mbps (1920x1080 CRF23
faststart, muted track dropped) — visually identical on this
illustrated content; cache-buster bumped to v=8.
- Video is <link rel=preload>ed the moment the splash is scheduled (the
<video> element only mounts ~20s in, so cold caches used to start the
download mid-sequence and stutter).
- nginx demo cache regex now covers mp4/webm/mp3/webp/woff2 so repeat
visits play from browser cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nginx regex locations outrank prefix locations, so app-shell assets like
/app/bitcoin-core/tailwind.css and /app/lnd/qrcode.js hit the .css/.js
cache block and 404'd from the web root instead of proxying to the mock
backend — the actual cause of the unstyled Bitcoin UI (and the shabby
lnd-ui) on the demo. ^~ on the /app/ prefixes disables regex matching
for those paths. Config validated with nginx -t.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mempool placeholder page (777d54ea) is served by the mock backend, but
the demo web nginx still had a location block reverse-proxying /app/mempool/
to mempool.guide, so it always won and the placeholder was unreachable.
Drop the block so mempool falls through to the generic /app/ backend proxy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Serve committed demo/content (music/photos/documents) alongside demo/files
drop-ins, normalizing top-level folder names; Dockerfile now COPYs it. This
is why Cloud music failed: the real library sat in demo/content while the
loader only read the empty demo/files.
- Drop unbacked seeded Videos; runtime WAV/SVG fallback for any seeded media
without a real file so playback never hits 'no supported source'.
- monitoring.current/history/alerts/alert-rules/export rewritten to the exact
MetricSnapshot shapes Monitoring.vue expects (epoch-second timestamps,
containers with limits/block IO, rpc_latency_ms, ws_connections).
- streaming.list-services + configure-service (Networking Profits page was
erroring with Method not found).
- server.get-state snapshot so the 30s resync / reconnect path stops erroring.
- lnd-connect-info now returns cert/macaroon base64url + grpc/rest ports (the
lnd-ui shell only renders the wallet QR + details when they're present);
LND REST balance endpoints for the shell's new balance cards.
- Fix broken icon paths (lnd.svg → lnd.png and 15 others) against real assets.
- containers-scanned: true so app cards never sit on 'Checking…'.
- 8 new installed demo apps with placeholder dashboard UIs (btcpay-server,
grafana, nextcloud, jellyfin, vaultwarden, nostr-rs-relay, searxng,
uptime-kuma) via the previously unused demoAppShell.
- WS heartbeat 45s → 20s (+ping 25s) so idle-timeout proxies in front of the
public demo stop killing the socket (the 'always reconnecting' report).
- nginx demo proxy: mempool.space → mempool.guide (mempool.space blocks the
proxied embed) + WebSocket upgrade passthrough; txid hydration follows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- IndeeHub + Mempool: nginx reverse-proxy + strip X-Frame-Options/CSP + sub_filter
rewrite of absolute asset paths so the frame-busting SPAs load in the iframe
(mempool.space remains best-effort — third-party CSP/ws may still limit it).
- AIUI iframe gets ?mockArchy in demo → its built-in mock node data loads.
- Pay-with-mobile QR: invoice settles after ~2s (backend gate keyed by
payment_hash) and the poll tightened to 1s, so the QR is visible before auto-pay.
- Wallet settings: dummy Cashu mints (4) + Fedimint federations (2, 222,500 sats),
interactive per session (streaming.list/configure-mints, wallet.fedimint-list/
join/balance).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mempool and IndeeHub load their real site directly in the iframe (reverted the
proxy/new-tab — per request "use https://indee.tx1138.com/").
- Real app UIs now served as whole static dirs under /app/<id>/ (express.static)
so their bundled assets (qrcode.js, css, bg images) resolve; /app/<id>/assets/*
redirect to the frontend's shared assets. Fixes the console 404 cascade.
- Bitcoin Core/Knots: register rpc/v1 + bitcoin-rpc on their paths (relay-status
no longer 404s); per-impl bitcoin-status preserved.
- AIUI chat returns a fixed line in demo ("Not available in demo, check out the
previous chats to experience AIUI") instead of calling Claude — no key spend.
- Add /api/app-catalog (serves the baked catalog) to stop that 404.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- App UIs now use the real registry shells with dummy data: bitcoin-ui for
Bitcoin Core (Satoshi subversion) and Bitcoin Knots (Knots subversion) via
per-path /app/bitcoin-{core,knots}/bitcoin-status; the real lnd-ui (mock
/proxy/lnd/v1/getinfo+channels, /lnd-connect-info, /api/container/logs); the
static fedimint-ui. ElectrumX already on the real electrs-ui. Custom mock UIs
dropped — accurate UX.
- IndeeHub loads in the iframe: nginx reverse-proxies /app/indeedhub/ →
indee.tx1138.com and strips X-Frame-Options/CSP (it blocked framing before).
- Mempool opens in a new tab (mempool.space can't be iframed).
- Cloud media playback: HTTP Range support in the curated-file server so audio/
video can stream and seek (needs real files dropped into demo/files/).
- Dockerfile/.dockerignore copy docker/lnd-ui + docker/fedimint-ui.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mock app UIs (ElectrumX, LND, Fedimint, Bitcoin Core) + the "Not available"
notice now use the Archipelago black theme and show the app's My-Apps icon.
- Bitcoin Core gets its own UI (/app/bitcoin-core/) so it no longer shows Bitcoin
Knots branding; the Knots-branded bitcoin-ui shell is reserved for Bitcoin Knots.
- ElectrumX now serves the real electrs-ui shell (+ qrcode.js + a dummy
/electrs-status) with the correct ElectrumX icon; "Electrs" renamed to ElectrumX.
- My Apps: pre-install Bitcoin Knots again, drop ThunderHub, rename Electrs→ElectrumX.
- App store no longer shows "Checking…" forever in demo — non-demoable apps show
"No demo" immediately (skip the container-scan state).
- Relay endpoint no longer reveals a real domain (randomised host).
- Dockerfile/.dockerignore copy docker/electrs-ui into the backend image.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- nginx-demo.conf + vite proxy now route every /app/<id>/ to the mock backend, so
the per-app mock UIs and the generic "Not available in the demo" notice render
(previously only /app/filebrowser was proxied → most apps 404'd).
- Mempool and IndeeHub now load in the in-app iframe (not a new tab).
- Add an LND Lightning mock UI (channels, balances, routing) with dummy data;
lnd/thunderhub are demoable. Notice page reworded to "Not available in the demo".
- Fix missing icons: Bitcoin Core → bitcoin-core.png, Mempool → mempool.webp.
- Pre-install only Bitcoin Core (drop duplicate Bitcoin Knots; still installable).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Container stability:
- Merge scan results instead of full replacement (prevents UI flapping)
- Absence threshold: 3 consecutive missed scans before removing from state
- container-list RPC uses cached scanner state for consistency
- Increased Podman API timeout 30s → 60s (scanner + health monitor)
- Keep crashed containers visible as "exited" instead of podman rm -f
- Resolve host-gateway IP via ip route (podman 4.3.x compatibility)
ISO build fixes:
- AIUI web app inclusion: searches 5 paths + CI step to copy from build server
- Claude API proxy: systemctl enable with symlink fallback
- AIUI nginx: try_files =404 (was /aiui/index.html redirect loop)
- Build version set to 1.3.0
Container fixes:
- lnd-ui: nginx listens on 8080 (was 80, Permission denied in rootless)
- first-boot: image-versions.sh sourced from correct path with validation
- first-boot: host-gateway resolved to actual gateway IP
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The entrypoint now injects client_max_body_size 0 at runtime if missing,
as a safety net against Docker layer caching of the nginx config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Location-level override wasn't sufficient. Setting at http block
disables the body size limit globally for the demo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create Ollama provider plugin in AIUI (ollama-provider.ts)
- Register Ollama alongside Claude in plugin system
- Auto-detect installed models via /api/tags endpoint
- Add Ollama proxy in mock backend (forwards to localhost:11434)
- Add nginx proxy rules for /aiui/api/ollama/ (both HTTP and HTTPS)
- Rebuild AIUI dist with Ollama provider included
- Qwen 2.5 Coder 3B installed on dev server via Ollama
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add /api/web-search stub returning empty results in demo mode
- Add /aiui/api/* catch-all returning JSON 404 instead of HTML fallback
- Fix nginx proxy to catch all /api/ routes (not just /aiui/api/web-search)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Inject max_tokens: 4096 in Claude API proxy when AIUI omits it
- Add /aiui/api/web-search stub returning empty results (no search backend in demo)
- Add nginx proxy rule for web-search endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Claude API proxy in mock-backend.js (reads ANTHROPIC_API_KEY from env)
- Supports SSE streaming via pipe
- Move ANTHROPIC_API_KEY to backend service in docker-compose.demo.yml
- Remove envsubst from entrypoint (no longer needed)
- nginx-demo.conf proxies /aiui/api/claude/ to backend
This fixes the 401 error when Portainer doesn't pass env vars to
nginx correctly — the Node.js backend reads process.env directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap ${ANTHROPIC_API_KEY} in quotes so envsubst produces valid nginx
directive even when the variable is empty
- Skip Docker container polling when runtime is unavailable (stops
log spam in demo/Portainer deployments)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add AIUI pre-built dist to demo/ for Portainer deployment
- Add nginx-demo.conf with Claude API proxy (envsubst for API key)
- Add docker-entrypoint.sh for runtime API key injection
- Update Dockerfile.web to include AIUI and Claude proxy
- Update docker-compose.demo.yml with ANTHROPIC_API_KEY env var
- Switch deploy script from sshpass to SSH key auth
- Fix Quick Start Goals animating before other cards (stagger 5, opacity guard)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>