# Archipelago App UI Standards - For Apps Without Native UIs **Version:** 1.0 **Last Updated:** 2026-02-03 ## Overview This document defines the **standard UI pattern** for containerized applications that don't have their own web interface (e.g., Bitcoin Core, LND, Core Lightning, mempool backend services, etc.). These UIs provide a simple, elegant way to: - Monitor service status and metrics - View connection information (RPC, REST, gRPC endpoints) - Access logs and settings - Copy configuration details for external tools --- ## Architecture ``` ┌─────────────────────────────────────┐ │ Nginx Container (Alpine) │ │ - Serves static HTML/CSS/JS │ │ - Port 8XXX (unique per service) │ │ - Optional: Proxies RPC/API calls │ └─────────────────────────────────────┘ ``` ### File Structure ``` docker/ ├── {service-name}-ui/ │ ├── index.html # Main UI file │ ├── Dockerfile # Container build │ ├── nginx.conf # Nginx config │ ├── {service-icon} # App icon (svg/webp/png) │ └── bg-{theme}.jpg # Background image ``` --- ## Standard UI Components ### 1. **CSS Class System** #### `.glass-card` - Main Container Cards Used for: Header, main sections, modals ```css .glass-card { position: relative; background: rgba(0, 0, 0, 0.60); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.22); border-radius: 1rem; overflow-x: hidden; overflow-y: visible; border: none; } .glass-card::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; z-index: 1; } .glass-card > * { position: relative; z-index: 2; } ``` #### `.info-card` - Stat Display Cards Used for: Status badges, metric displays (non-interactive) ```css .info-card { position: relative; background: rgba(0, 0, 0, 0.60); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.22); border-radius: 16px; padding: 12px; border: none; } .info-card::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; } ``` **No hover effects** - These are display-only elements. #### `.info-card-button` - Interactive Action Buttons Used for: Primary action buttons (Copy Info, View Logs, etc.) ```css .info-card-button { /* Same base styles as .info-card */ position: relative; background: rgba(0, 0, 0, 0.60); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.22); border-radius: 16px; padding: 12px; transition: all 0.3s ease; border: none; cursor: pointer; color: rgba(255, 255, 255, 0.9); } .info-card-button::before { /* Same gradient as .info-card */ content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; transition: all 0.3s ease; } /* Hover state - lifts and brightens */ .info-card-button:hover { transform: translateY(-2px); background: rgba(0, 0, 0, 0.35); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.25); color: rgba(255, 255, 255, 1); } .info-card-button:hover::before { background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), transparent); } /* Active state - press down */ .info-card-button:active { transform: translateY(1px); } ``` #### `.glass-button` - Secondary Buttons Used for: Settings, Close (×), secondary actions ```css .glass-button { background-color: rgba(0, 0, 0, 0.6); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); border: 1px solid rgba(255, 255, 255, 0.18); color: rgba(255, 255, 255, 0.9); transition: all 0.3s ease; } .glass-button:hover { color: white; background-color: rgba(0, 0, 0, 0.7); } ``` #### Simple Info Rows - `bg-white/5` Used for: Non-interactive info rows (RPC Host, Network, Status, etc.) ```html
Label
Value
``` **No gradient borders** - These are simple read-only display elements. --- ## Standard Layout Pattern ### 1. **Header Section** (`.glass-card`) ```html
{Service Name}

{Service Name}

{Service Description}

``` ### 2. **Quick Status Bar** (`.glass-card` with `.info-card` grid) ```html
``` ### 3. **Main Content Sections** (`.glass-card` grid) ```html

Section Title

Section description

``` ### 4. **Modals** (`.glass-card` with backdrop) ```html ``` --- ## Visual Hierarchy ### **Container Importance (Most → Least)** 1. **`.glass-card`** - Main containers, sections, modals - Gradient border, strong blur (24px), inset highlights 2. **`.info-card`** - Stat displays, status badges - Gradient border, backdrop blur, **NO hover effects** 3. **`.info-card-button`** - Primary action buttons - Same as `.info-card` in default state - **WITH hover effects** (lift, brighten, enhanced gradient) 4. **`bg-white/5`** - Simple info rows - Dark background, **NO borders**, **NO hover** 5. **`.glass-button`** - Secondary buttons - Simple glass effect, minimal hover --- ## Port Assignments Reserve unique ports for each service UI: ``` 8334 - Bitcoin Knots UI 8081 - LND UI 8082 - Core Lightning UI (future) 8083 - Mempool UI (future) 8084 - BTCPay Server UI (future) ... ``` Update backend's `docker_packages.rs` to map these ports: ```rust } else if app_id == "lnd" { Some("http://localhost:8081".to_string()) } else if app_id == "bitcoin-knots" { Some("http://localhost:8334".to_string()) } ``` --- ## Dockerfile Template ```dockerfile FROM docker.io/library/nginx:alpine # Copy the HTML file COPY index.html /usr/share/nginx/html/ # Create directories for assets RUN mkdir -p /usr/share/nginx/html/assets/img/app-icons && \ mkdir -p /usr/share/nginx/html/assets/img # Copy assets COPY {service-icon} /usr/share/nginx/html/assets/img/app-icons/ COPY bg-{theme}.jpg /usr/share/nginx/html/assets/img/ # Copy nginx config COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` --- ## Nginx Config Template ### Simple Static Serving (LND, most services) ```nginx server { listen 8XXX; # Unique port for this service server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } } ``` ### With RPC Proxy (Bitcoin Knots) ```nginx server { listen 8334; server_name _; root /usr/share/nginx/html; index index.html; # RPC proxy to avoid CORS issues location /bitcoin-rpc/ { proxy_pass http://127.0.0.1:8332/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Authorization "Basic {BASE64_ENCODED_CREDS}"; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; if ($request_method = OPTIONS) { return 204; } } location / { try_files $uri $uri/ /index.html; } } ``` --- ## Deployment ### Build and Run ```bash # Build the image cd docker/{service}-ui sudo podman build -t {service}-ui:latest . # Run the container sudo podman run -d \ --name {service}-ui \ --restart unless-stopped \ --network=host \ --label 'com.archipelago.parent-app={service-id}' \ {service}-ui:latest ``` ### Backend Integration Update `core/archipelago/src/container/docker_packages.rs`: ```rust } else if app_id == "{service-id}" { Some("http://localhost:8XXX".to_string()) } ``` --- ## Reference Implementations ### ✅ Bitcoin Knots UI - **Location:** `docker/bitcoin-ui/` - **Port:** 8334 - **Features:** - Live sync status with animations - RPC proxy for CORS handling - Real-time block updates - Connection info display ### ✅ LND UI - **Location:** `docker/lnd-ui/` - **Port:** 8081 - **Features:** - Node status monitoring - Channel count display - REST API + gRPC info - Settings and logs modals --- ## Benefits of This Approach 1. **Consistency** - All service UIs look and feel the same 2. **Lightweight** - Nginx Alpine base (~10MB) 3. **Fast Development** - Copy template, customize content 4. **Mobile Responsive** - Works on all screen sizes 5. **Low Resource Usage** - Static files, minimal CPU/RAM 6. **Easy Maintenance** - Single pattern to update globally --- ## Creating a New Service UI ### Step-by-Step Process 1. **Create Directory Structure** ```bash mkdir -p docker/{service}-ui cd docker/{service}-ui ``` 2. **Copy Template Files** ```bash cp ../bitcoin-ui/index.html ./ cp ../bitcoin-ui/Dockerfile ./ cp ../bitcoin-ui/nginx.conf ./ ``` 3. **Customize `index.html`** - Update title, service name, description - Modify status cards for your service's metrics - Update connection info sections (RPC/REST/gRPC) - Adjust modal content 4. **Copy Assets** ```bash cp ../../neode-ui/public/assets/img/app-icons/{service-icon} ./ cp ../../neode-ui/public/assets/img/bg-{theme}.jpg ./ ``` 5. **Update Nginx Config** - Set unique port number - Add RPC proxy if needed 6. **Update Dockerfile** - Update asset COPY commands - Verify port EXPOSE 7. **Build and Deploy** ```bash # Deploy to dev server sshpass -p "archipelago" rsync -avz --delete ./ archipelago@192.168.1.228:/tmp/{service}-ui-build/ # Build on server sshpass -p "archipelago" ssh archipelago@192.168.1.228 \ "cd /tmp/{service}-ui-build && \ sudo podman build -t {service}-ui:latest . && \ sudo podman stop {service}-ui 2>/dev/null || true && \ sudo podman rm {service}-ui 2>/dev/null || true && \ sudo podman run -d --name {service}-ui --restart unless-stopped \ --network=host --label 'com.archipelago.parent-app={service-id}' \ {service}-ui:latest" ``` 8. **Update Backend** - Edit `core/archipelago/src/container/docker_packages.rs` - Add port mapping for your service --- ## Testing Checklist - [ ] UI loads correctly at `http://{server}:8XXX/` - [ ] Logo displays properly - [ ] Background image loads - [ ] All status cards show correct info - [ ] Buttons have proper hover effects - [ ] Modals open and close correctly - [ ] Mobile responsive (test on phone) - [ ] Glass effects render correctly - [ ] Gradient borders visible - [ ] Cache busting works (no stale content) --- ## Future Enhancements - **Live Data Updates** - WebSocket connections for real-time status - **Interactive Charts** - Add Chart.js for visualizing metrics - **Theme Variations** - Allow users to select background themes - **Dark/Light Mode** - Toggle between color schemes - **Internationalization** - Support multiple languages - **Accessibility** - Improve screen reader support --- ## File Locations - **UI Standards Doc:** `/Users/dorian/Projects/archy/.cursor/rules/APP-UI-STANDARDS.md` - **Global UI Standards:** `/Users/dorian/Projects/archy/.cursor/rules/UI-STANDARDS.md` - **Reference Implementations:** - Bitcoin UI: `/Users/dorian/Projects/archy/docker/bitcoin-ui/` - LND UI: `/Users/dorian/Projects/archy/docker/lnd-ui/` --- **Version:** 1.0 **Maintained by:** Archipelago Development Team **Last Updated:** 2026-02-03