5.7 KiB
Archipelago Public Demo — build info & status
Status: implemented & deployable (2026-06-22)
Branch: demo-build (worktree ../archy-demo-build), pushed to
gitea-vps2 = http://146.59.87.168:3000/lfg2025/archy.git.
Main/prod is untouched — all demo work lives only on demo-build.
A public, click-to-play demo of the Archipelago UI, 100% mock-data driven,
multi-visitor, deployed via Portainer. See also docs/demo-deployment-design.md
(original design) and demo-deploy/ (thin prebuilt-image stack).
Deploy (Portainer)
Build-from-repo (works today, no registry needed):
| Field | Value |
|---|---|
| Repository URL | http://146.59.87.168:3000/lfg2025/archy.git |
| Reference | refs/heads/demo-build |
| Compose path | docker-compose.demo.yml |
| Auth | user lfg2025, password = Gitea token |
| UI port | 2100 · Login password: entertoexit |
Redeploy after each push. docker-compose.demo.yml builds two images
(neode-ui/Dockerfile.backend = mock server, neode-ui/Dockerfile.web = nginx+UI).
The thin demo-deploy/docker-compose.yml pulls prebuilt :demo images instead
(needs the CI image pipeline / registry wired — .github/workflows/demo-images.yml).
Flags / env
- Backend:
DEMO=1(compose sets it) → multi-session sandbox, no real runtime. - Web build:
VITE_DEMO=1(Dockerfile.web ARG, default 1) → inlined demo UI behaviour. - Optional:
ANTHROPIC_API_KEY(NOT needed — AIUI chat is canned in demo),DEMO_SESSION_TTL_MS(45m),DEMO_MAX_SESSIONS(500),DEMO_FILE_QUOTA_BYTES(50MB).
Architecture
Everything is gated behind DEMO (off = classic single-user dev mock, unchanged).
neode-ui/mock-backend.js— the entire fake backend (Node/Express, ~95+ RPCs).- Per-session isolation:
AsyncLocalStorage+ Proxy. Globals (mockData,walletState,userState,mockState,bitcoinRelayMockState) are Proxies that resolve to the current request's store, keyed by ademo_sidcookie. Deep-cloned fromSEED_*on first hit; idle-reaped; per-session WS fan-out. - Files: per-session in-memory store + curated disk files (see below).
- Forces simulation mode in DEMO (
docker=null).
- Per-session isolation:
neode-ui/src/composables/useDemoIntro.ts— the frontend demo switch (IS_DEMO), per-day intro gate,DEMO_PASSWORD, app demoability + launch URLs.neode-ui/docker/nginx-demo.conf— routes/rpc,/ws,/app/*,/electrs-status,/proxy/,/lnd-connect-info, the IndeeHub/Mempool reverse-proxies, and the SPA.docker/{bitcoin-ui,electrs-ui,lnd-ui,fedimint-ui}/— the REAL registry app UIs, served statically under/app/<id>/with mocked data endpoints.demo/aiui/— prebuilt AIUI dist (chat is canned;?mockArchy&seed).demo/files/— curated cloud files drop-in (see below).
Demo features (all implemented)
Per-session sandbox · per-session file upload (Range streaming) · testnet/signet
flavor · per-day intro replay · entertoexit login (prefilled + hint) · version
<real>-demo · onboarding wizard skipped (intro kept) · "No demo" install gating ·
real app UIs (Bitcoin Core vs Knots by subversion, ElectrumX, LND, Fedimint;
Mempool/IndeeHub iframed) · 12 federation nodes / 5 peers · FIPS active · interactive
buy flow (testnet addresses, bolt11, 2s QR) · real testnet tx links (mempool.space) ·
networking profits 5,231,978 sats + labelled wallet txs · VPN · Nostr relays ·
node-visibility toggle · dummy Cashu mints + Fedimint federations · AIUI canned
reply + ?mockArchy mock data + ?seed pre-loaded "Content Showcase" chat.
Curated cloud files (demo/files/)
Drop real files into demo/files/<Folder>/<file> and commit — they become the
cloud content for every visitor (read-only; git access = the "private login").
Loader merges per top-level folder: adding Music/ swaps only Music and keeps
the sample Documents/Photos/Videos. Empty → built-in seeds. Text inlined; binaries
streamed from disk with HTTP Range (seek). Backend reads /demo/files —
Dockerfile.backend COPYs it; .dockerignore must allow it.
Gotchas (READ before editing)
- Sibling dirs need both the Dockerfile COPY and a
.dockerignoreallow.docker/bitcoin-ui,docker/electrs-ui,docker/lnd-ui,docker/fedimint-ui,demo/filesare outsideneode-ui/; they're copied into the backend image and un-ignored in.dockerignore(*+!docker/+docker/*+!docker/<ui>/). Forgetting either → Portainer build "not found" or runtime 500/404. - Real app UIs assume root-serving — served via
express.static('/app/<id>')/app/<id>/assets/*→/assets/*redirect + per-path data endpoints (bitcoin-status,rpc/v1,bitcoin-rpc/,/proxy/lnd/*,/electrs-status).
- Uploaded-via-UI files are ephemeral (per-session, lost on redeploy/reap).
Only
demo/files/persists. - Mempool iframe is best-effort (third-party CSP/websockets). IndeeHub is
reverse-proxied with header-strip +
sub_filterasset rewrite; if still black, it's indee's ownX-Frame-Options(fix on that server). - AIUI
?seedbootstrap hardcodes the current AIUI bundle hash (/aiui/assets/seedPrompts-CLWaUv28.js) — re-paste if AIUI is rebuilt. Tiny first-load IndexedDB race (one refresh shows the chat). - Running mock-backend.js locally in the sandbox is flaky: start backgrounded,
sleep 5+, then curl; NEVERpkill -f mock-backend(it matches & kills the shell) — usepkill -x node. - Delete-405 seen pre-redeploy was nginx/stale; backend DELETE returns 200.
Commit trail (demo-build, newest last)
2715f2d8 sandbox → … → 7efebb4a media merge + AIUI seed. ~14 commits, all
feat(demo)/fix(demo).