feat: complete Phase 1 foundation hardening + three-mode UI design doc
Phase 1a — Gradient Removal: - Replaced all gradient-button/gradient-card with glass-button/path-option-card - Removed banned gradient CSS classes Phase 1b — Security Hardening: - SecretsManager: AES-256-GCM encryption (core/security) - electrs_status: credentials from env vars instead of hardcoded - port_manager: RwLock proper error handling (no unwrap) - Pinned all 11 :latest manifest images to specific versions - parmanode converter: pinned inferred image versions Phase 1c — Code Quality: - Split rpc.rs (1795 lines) into 6 handler modules (auth, node, container, package, peers) - Removed sideload code (UI, store, RPC client, 3 doc files) - Fixed body background flash on logout/refresh - Replaced 30 TypeScript `any` types with proper types - Deleted HelloWorld.vue, removed TODO comments - Added set -euo pipefail to all shell scripts - Made deploy script verbose with timestamps and elapsed time Also adds: - CLAUDE.md project guide - docs/three-mode-ui-design.md — design spec for Easy/Pro/Chat UI modes - OnlineStatusPill component Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
62d6c13764
commit
486fc39249
+26
-21
@@ -25,11 +25,14 @@ ARCHIPELAGO_PASSWORD="${ARCHIPELAGO_PASSWORD:-archipelago}"
|
||||
# Force password auth when using sshpass (avoids "Permission denied" from SSH key mismatch)
|
||||
SSH_OPTS="-o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no"
|
||||
|
||||
DEPLOY_START=$(date +%s)
|
||||
timestamp() { echo "[$(date +%H:%M:%S)]"; }
|
||||
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ Deploying to Archipelago Target ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Target: $TARGET_HOST"
|
||||
echo "$(timestamp) Target: $TARGET_HOST"
|
||||
echo ""
|
||||
|
||||
# Parse arguments
|
||||
@@ -70,7 +73,7 @@ if [ "$BOTH" = true ]; then
|
||||
fi
|
||||
|
||||
# Sync code
|
||||
echo "📦 Syncing code..."
|
||||
echo "$(timestamp) 📦 Syncing code..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" rsync -avz --delete \
|
||||
-e "ssh $SSH_OPTS" \
|
||||
--exclude 'node_modules' \
|
||||
@@ -89,33 +92,33 @@ fi
|
||||
|
||||
# Build on target
|
||||
echo ""
|
||||
echo "🔨 Building on target..."
|
||||
echo "$(timestamp) 🔨 Building on target..."
|
||||
|
||||
# Frontend
|
||||
echo " Building frontend..."
|
||||
echo "$(timestamp) Building frontend (vue-tsc + vite)..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/neode-ui && npm install --silent && npm run build" 2>&1 | sed 's/^/ /'
|
||||
|
||||
# Backend (if Rust is installed)
|
||||
if sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "source ~/.cargo/env 2>/dev/null && command -v cargo" >/dev/null 2>&1; then
|
||||
echo " Building backend..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "source ~/.cargo/env && cd $TARGET_DIR/core && cargo build --release 2>&1" | tail -10 | sed 's/^/ /'
|
||||
echo "$(timestamp) Building backend (Rust release — this takes 1-2 min)..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "source ~/.cargo/env && cd $TARGET_DIR/core && cargo build --release 2>&1" | sed 's/^/ /'
|
||||
else
|
||||
echo " ⚠️ Rust not installed on target, skipping backend build"
|
||||
fi
|
||||
|
||||
if [ "$LIVE" = true ]; then
|
||||
echo ""
|
||||
echo "🚀 Deploying to live system..."
|
||||
|
||||
echo "$(timestamp) 🚀 Deploying to live system..."
|
||||
|
||||
# Deploy backend (check if binary exists)
|
||||
if sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "[ -f $TARGET_DIR/core/target/release/archipelago ]" 2>/dev/null; then
|
||||
echo " Deploying backend binary..."
|
||||
echo "$(timestamp) Deploying backend binary..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo systemctl stop archipelago"
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo cp $TARGET_DIR/core/target/release/archipelago /usr/local/bin/"
|
||||
fi
|
||||
|
||||
# Deploy frontend
|
||||
echo " Deploying frontend..."
|
||||
echo "$(timestamp) Deploying frontend..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo rm -rf /opt/archipelago/web-ui/*"
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo cp -r $TARGET_DIR/web/dist/neode-ui/* /opt/archipelago/web-ui/"
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo chown -R 1000:1000 /opt/archipelago/web-ui"
|
||||
@@ -157,15 +160,15 @@ if [ "$LIVE" = true ]; then
|
||||
fi
|
||||
|
||||
# Restart services
|
||||
echo " Restarting services..."
|
||||
echo "$(timestamp) Restarting services..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo systemctl start archipelago && sudo systemctl restart nginx"
|
||||
|
||||
# Set up HTTPS for PWA installability (browsers require secure context)
|
||||
echo " Setting up HTTPS for PWA install..."
|
||||
echo "$(timestamp) Setting up HTTPS for PWA install..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "sudo bash $TARGET_DIR/scripts/setup-https-dev.sh" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Rebuild and recreate LND UI container (port 8081 so Launch from UI and http://host:8081 both work)
|
||||
echo " Rebuilding LND UI..."
|
||||
echo "$(timestamp) Rebuilding LND UI..."
|
||||
if sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/lnd-ui && (command -v podman >/dev/null 2>&1 && sudo podman build --no-cache -t lnd-ui:latest . || sudo docker build --no-cache -t lnd-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
echo " Recreating LND UI container (port 8081)..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
@@ -179,7 +182,7 @@ if [ "$LIVE" = true ]; then
|
||||
fi
|
||||
|
||||
# Rebuild and recreate Electrs UI container (port 50002)
|
||||
echo " Rebuilding Electrs UI..."
|
||||
echo "$(timestamp) Rebuilding Electrs UI..."
|
||||
if sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/electrs-ui && (command -v podman >/dev/null 2>&1 && sudo podman build --no-cache -t electrs-ui:latest . || sudo docker build --no-cache -t electrs-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
echo " Recreating Electrs UI container (port 50002, host network)..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
@@ -194,7 +197,7 @@ if [ "$LIVE" = true ]; then
|
||||
|
||||
# Bitcoin Knots: required for Mempool, Electrs, BTCPay, Fedimint
|
||||
TARGET_IP="$(echo "$TARGET_HOST" | cut -d@ -f2)"
|
||||
echo " Ensuring Bitcoin Knots (required for Electrs/Mempool)..."
|
||||
echo "$(timestamp) Ensuring Bitcoin Knots..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
@@ -218,7 +221,7 @@ if [ "$LIVE" = true ]; then
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Fix Mempool: clean duplicates, ensure full stack - mysql, backend (8999), frontend (4080)
|
||||
echo " Fixing Mempool stack (host=$TARGET_IP)..."
|
||||
echo "$(timestamp) Fixing Mempool stack..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
@@ -322,7 +325,7 @@ if [ "$LIVE" = true ]; then
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Fix BTCPay Server: requires PostgreSQL + NBXplorer (BTCPay needs NBXplorer for block indexing)
|
||||
echo " Fixing BTCPay Server stack..."
|
||||
echo "$(timestamp) Fixing BTCPay Server stack..."
|
||||
TARGET_IP="$(echo "$TARGET_HOST" | cut -d@ -f2)"
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
@@ -397,7 +400,7 @@ if [ "$LIVE" = true ]; then
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Ensure Immich stack (postgres + redis + server) - creates if missing
|
||||
echo " Ensuring Immich stack (port 2283)..."
|
||||
echo "$(timestamp) Ensuring Immich stack..."
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
@@ -439,7 +442,7 @@ if [ "$LIVE" = true ]; then
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Tor: global hidden services - each service gets its own .onion address
|
||||
echo " Setting up Tor (hidden services for each app)..."
|
||||
echo "$(timestamp) Setting up Tor..."
|
||||
TARGET_IP="$(echo "$TARGET_HOST" | cut -d@ -f2)"
|
||||
sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
@@ -505,7 +508,7 @@ if [ "$LIVE" = true ]; then
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Recreate Fedimint with FM_API_URL for Guardian UI (fixes "Api URL must be configured")
|
||||
echo " Fixing Fedimint API URL..."
|
||||
echo "$(timestamp) Fixing Fedimint API URL..."
|
||||
TARGET_IP="$(echo "$TARGET_HOST" | cut -d@ -f2)"
|
||||
TIMEOUT_CMD=""
|
||||
command -v timeout >/dev/null 2>&1 && TIMEOUT_CMD="timeout 90"
|
||||
@@ -535,8 +538,10 @@ if [ "$LIVE" = true ]; then
|
||||
done
|
||||
" 2>&1 | sed 's/^/ /') || echo " (Fedimint fix timed out or skipped - run manually if needed)"
|
||||
|
||||
DEPLOY_END=$(date +%s)
|
||||
DEPLOY_ELAPSED=$((DEPLOY_END - DEPLOY_START))
|
||||
echo ""
|
||||
echo "✅ Deployed to live system!"
|
||||
echo "$(timestamp) ✅ Deployed to live system! (${DEPLOY_ELAPSED}s total)"
|
||||
echo " Backend: $(sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" 'sudo systemctl is-active archipelago')"
|
||||
echo " Web UI: http://$(echo $TARGET_HOST | cut -d@ -f2)"
|
||||
echo " PWA install: https://$(echo $TARGET_HOST | cut -d@ -f2) (use HTTPS, accept cert once, then Install app)"
|
||||
|
||||
Reference in New Issue
Block a user