Files
archy/docs/demo-build-info.md
T
archipelagoandClaude Opus 5 8e814ca06a
Demo images / Build & push demo images (push) Failing after 2m22s
feat(registry): move image and OTA references to the public domain
Replaces the registry host across 86 files: 309 references, covering all 40
app manifests, the orchestrator and container crates, the release and catalog
scripts, both demo-images workflows, the ISO builder, demo-deploy, and the
frontend marketplace data.

Verified the domain actually serves the registry before rewriting anything,
rather than assuming the web host implies the registry:
- TLS verifies clean, HTTP/2 on the web root
- an anonymous token grants a manifest fetch (HTTP 200) with no credentials
- skopeo inspect --no-creds resolves an image and lists its tags

That last check is the one that matters: an outside developer with no account
can now pull, which was the functional blocker for publishing at all.

Plain-HTTP references become HTTPS in the same pass, so OTA downloads stop
crossing the network in the clear.

Deliberately NOT rewritten:
- The public FIPS anchor on port 8444. It is a functional network endpoint
  every node dials to bootstrap the mesh — closer to Bitcoin Core's hardcoded
  seeds than to leaked infrastructure. The domain does resolve to the same
  host, so it could become a hostname, but that adds a DNS dependency to the
  path used precisely when things are broken. Worth a deliberate decision,
  not a side effect of this change.
- The companion APK on port 2100. The domain returns 404 for that path, so
  rewriting it would swap a working URL for a broken one. The Releases page
  does serve (200), which is where the plan already wants those binaries.
- releases/app-catalog.json, releases/manifest.json and release-manifest.json.
  These carry `signature` and `signed_by`; editing their contents invalidates
  the signature and the fleet refuses artifacts that fail verification. They
  were rewritten in a first pass and reverted — they must be regenerated and
  re-signed through the signing ceremony instead, which needs the mnemonic.

So the catalog still advertises the old host until that ceremony runs. Nodes
resolve images through the signed catalog, not the on-disk manifests, so this
commit alone does not change what a node pulls.

Verified: archipelago-container 75/75; every manifest still parses with a
top-level app block; no signed artifact modified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 11:31:20 -04:00

5.7 KiB

Archipelago Public Demo — build info & status

Status: implemented & deployable (2026-07-14) Branch: main — the demo machinery was merged from the old demo-build branch and now lives on main, pushed to gitea-vps2 = https://source.archipelago-foundation.org/lfg2025/archy.git.

A public, click-to-play demo of the Archipelago UI, 100% mock-data driven, multi-visitor, deployed via Portainer. See also docs/archive/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 https://source.archipelago-foundation.org/lfg2025/archy.git
Reference refs/heads/main
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 a demo_sid cookie. Deep-cloned from SEED_* 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).
  • 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/filesDockerfile.backend COPYs it; .dockerignore must allow it.


Gotchas (READ before editing)

  • Sibling dirs need both the Dockerfile COPY and a .dockerignore allow. docker/bitcoin-ui, docker/electrs-ui, docker/lnd-ui, docker/fedimint-ui, demo/files are outside neode-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_filter asset rewrite; if still black, it's indee's own X-Frame-Options (fix on that server).
  • AIUI ?seed bootstrap 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; NEVER pkill -f mock-backend (it matches & kills the shell) — use pkill -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).