archy/neode-ui
archipelago e6ed5536c9
Some checks failed
Demo images / Build & push demo images (push) Failing after 3m46s
feat(02-06): cache the Server tab's seven load groups with explicit TTL/persist
Server.vue already had five of the seven load groups (network summary, FIPS
summary, VPN peers, interfaces, Tor services) on useCachedResource from a
pre-phase commit, but none declared an explicit ttlMs/persist (relying on
the composable's 30s/persist:true defaults) and dedup:true was missing from
several underlying RPC calls. loadDiskStatus was the one remaining plain
uncached fetch, forced on every activation.

- Explicit TTL per group (10s fast tier: network-summary/interfaces/
  disk-status; 30s near-default: vpn-peers/tor-services; 60s near-static:
  fips-summary)
- Explicit persist:false for server.vpn-peers (npub/peer identity) and
  server.tor-services (onion addresses) per T-02-01; other groups persist
- New server.disk-status cached resource replaces the plain fetch; it now
  self-heals via the composable's own onActivated instead of an explicit
  every-entry call
- dedup:true added to all underlying rpcClient calls, including the
  parameterless vpnStatus()/dnsStatus()/diskStatus() convenience methods
- RefreshIndicator wired into a new minimal header row, driven by whether
  any of the six cache entries is refreshing
- RESEARCH assumption A3 settled: read all seven loader bodies; none
  consumes another's result — the concurrent fan-out is correct as-is
- Fixed a keepAliveLifecycle.test.ts assertion invalidated by the new 10s
  network-summary TTL (reactivation now also revalidates that resource,
  adding one more vpnStatus() call the test didn't previously account for)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 17:03:55 -04:00
..
2026-01-24 22:59:20 +00:00
2026-05-05 11:29:18 -04:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00
2026-07-29 08:35:38 -04:00
2026-01-24 22:59:20 +00:00
2026-06-12 03:00:15 -04:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00

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:

  1. Stacks > Add stack > name: archy-demo
  2. Web editor: paste docker-compose.demo.yml contents
  3. Add environment variable: ANTHROPIC_API_KEY (for Claude chat)
  4. 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.css only — never inline Tailwind in components
  • .gradient-button is 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)
  • Production deploy: via scripts/deploy-to-target.sh --live

License

MIT