Open-source readiness plan, Phase 1 items 3 and 5. Item 3 turned out to be far narrower than the plan's "93 files" once each hit was classified rather than bulk-replaced. Sanitized only genuine operator identifiers: - FIPS test fixtures and a pine_ha comment carried real node LAN addresses -> RFC 5737 TEST-NET-1, the convention already used elsewhere in this repo. - Real tailnet addresses in fips/endpoints.rs, mock-backend.js and the mesh test runner -> the base of the CGNAT range, obviously synthetic. - Incident comments in appgate/mod.rs and apps/fedimint/manifest.yml named a specific node; the role is what carries the meaning, so the address is gone. - CHANGELOG.md held five real addresses in published release notes — the most exposed of the lot. Deliberately NOT touched, because the plan's item-3 list is over-broad and following it literally would break working code: - 192.168.1.1 / .254, 192.168.0.0/16 and 100.64.0.0/10 are generic router defaults, RFC1918 classification in backup_rpc, and CGNAT range logic in pine_ha / CompanionIntroOverlay. Not leaked infra. - `tx1138` is listed as a hostname to scrub but is two live things: the user-facing default block explorer (`DEFAULT_TX_EXPLORER`) and `RETIRED_TX1138_HOST`, the migration constant whose entire job is stripping that retired registry from existing nodes' saved mirror lists. Scrubbing either breaks a feature. The plan needs this correction. - Android's `192.168.1.100` strings are UI placeholder text. Item 5: added *.key, *.pem, id_rsa*, *.sqlite, *.db to .gitignore, with a negation for core/archipelago/src/appgate/testdata/*.key. Checked those first — they are documented throwaway TLS fixtures compiled in via include_bytes!, not node identity — and the negation stops the new rule silently dropping them if they are ever regenerated. Verified both directions: fixtures not ignored, a stray key elsewhere caught. Verified: residual grep for real infra addresses is clean; audit-secrets.sh still 5/5; app-catalog drift 0 (the fedimint edit is a YAML comment, which does not survive parsing into the signed catalog); 44/44 fips tests pass with the rewritten assertion fixtures. Note: these test runs shared the working tree with another agent's in-flight LND work, which was present but unstaged and is not part of this commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Archipelago Web UI
Vue 3 + TypeScript + Vite + Tailwind CSS + Pinia
The web interface for Archipelago — a self-sovereign Bitcoin Node OS.
Quick Start
cd neode-ui
npm install
npm start
Visit http://localhost:8100 — login with password: password123
This starts:
- Mock backend on port 5959 (no Docker required)
- Vite dev server on port 8100 with HMR
Stop with npm stop.
Architecture
neode-ui/
├── src/
│ ├── api/ # RPC client (rpc-client.ts), WebSocket, container client
│ ├── stores/ # Pinia stores (app, container, appLauncher, monitoring)
│ ├── views/ # Page components (Dashboard, Marketplace, Settings, etc.)
│ ├── components/ # Reusable components (SplashScreen, AppSession, etc.)
│ ├── router/ # Vue Router configuration
│ ├── types/ # TypeScript type definitions
│ └── style.css # Global styles + Tailwind utilities
├── public/assets/ # Static assets (images, fonts, app icons, audio)
├── mock-backend.js # Mock backend server (simulates Rust backend)
├── docker/ # Docker configs (nginx, entrypoint)
└── vite.config.ts # Vite config with backend proxy
Dev Modes
The mock backend supports multiple startup modes via VITE_DEV_MODE:
| Mode | Command | Behavior |
|---|---|---|
| default | npm start |
Fully set up, login screen |
| existing | VITE_DEV_MODE=existing npm run dev:mock |
Same as default |
| setup | VITE_DEV_MODE=setup npm run dev:mock |
First-time password setup flow |
| onboarding | VITE_DEV_MODE=onboarding npm run dev:mock |
Post-setup onboarding flow |
| boot | npm run dev:boot |
25s simulated boot sequence |
Mock Backend
The mock backend (mock-backend.js) simulates the full Rust backend for local development:
Pre-installed apps (always visible in My Apps):
- Bitcoin Core, LND, Electrs, Mempool, FileBrowser, LoraBell, Fedimint
Marketplace: 30+ curated apps with Docker images, install/uninstall simulation
Features simulated:
- Authentication (login, password change, TOTP 2FA)
- System metrics (CPU, memory, disk — randomized for realism)
- Node identity (DID, Nostr pubkey, Tor address)
- Federation (3 mock nodes with apps, metrics, trust levels)
- Mesh networking (4 LoRa peers, encrypted messaging, invoices)
- Peer-to-peer messaging
- FileBrowser API (mock file system with Music, Documents, Photos, Videos)
- DWN sync status
- Transport layer (mesh/LAN/Tor routing)
- Notifications (5 realistic entries)
- Claude AI chat proxy (requires
ANTHROPIC_API_KEY)
Container runtime: If Docker/Podman is available, the mock backend will run real containers for installed apps. Otherwise, it simulates them.
Demo Deployment (Portainer)
Deploy the demo via Docker Compose for showcasing:
docker compose -f docker-compose.demo.yml build
docker compose -f docker-compose.demo.yml up -d
Or deploy through Portainer Stacks:
- Stacks > Add stack > name:
archy-demo - Web editor: paste
docker-compose.demo.ymlcontents - Add environment variable:
ANTHROPIC_API_KEY(for Claude chat) - Deploy
Access at http://your-host:4848 — password: password123
Development Commands
npm start # Start mock backend + Vite (recommended)
npm stop # Stop all servers
npm run dev:mock # Same as start, without port cleanup
npm run dev:boot # Boot mode (simulated startup delay)
npm run backend:mock # Mock backend only
npm run dev # Vite only (needs backend running separately)
npm run dev:real # Vite with real Rust backend
npm run build # Production build (outputs to ../web/dist/neode-ui/)
npm run build:docker # Build for Docker (no type checking)
npm run type-check # TypeScript type checking
npm test # Run tests
Design System
Glass Classes
| Class | Use |
|---|---|
.glass-card |
Content containers, modals, panels |
.glass-button |
ALL buttons (primary and secondary) |
.path-option-card |
Interactive cards with hover lift |
.info-card |
Status badges, metric displays |
Tokens
- Font: Avenir Next (primary), Montserrat (
font-archipelago) - Glass:
bg: rgba(0,0,0,0.60),blur: 24px,border: rgba(255,255,255,0.22) - Accent:
#fb923c(Bitcoin orange),#4ade80(green),#ef4444(red) - Text:
rgba(255,255,255,0.9)primary,rgba(255,255,255,0.6)muted
Rules
- Global CSS classes in
style.cssonly — never inline Tailwind in components .gradient-buttonis banned — use.glass-button- All components use
<script setup lang="ts">
API
import { rpcClient } from '@/api/rpc-client'
await rpcClient.login('password')
await rpcClient.startPackage('bitcoin')
const metrics = await rpcClient.getMetrics()
State management via Pinia stores. WebSocket patches applied automatically.
Build Output
- Dev build:
../web/dist/neode-ui/ - Docker build:
dist/(deployed to nginx)
License
MIT