maneshtrader/skills/macos-selfcontained-webapp/references/implementation-blueprint.md

2.8 KiB

Implementation Blueprint

Backend Build Script (Python Example)

#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WEB_SRC_DIR="$ROOT_DIR/web/src"
MAC_SRC_DIR="${MAC_SRC_DIR:-$ROOT_DIR/mac/src}"
PYTHON_BIN="$ROOT_DIR/.venv/bin/python"
BACKEND_BIN_NAME="${BACKEND_BIN_NAME:-WebBackend}"
BUILD_ROOT="$ROOT_DIR/dist-backend-build"
DIST_PATH="$BUILD_ROOT/dist"
WORK_PATH="$BUILD_ROOT/build"
SPEC_PATH="$BUILD_ROOT/spec"
PROJECT_PATH="${MAC_PROJECT_PATH:-}"
SCHEME="${MAC_SCHEME:-}"
TARGET_DIR="${EMBEDDED_BACKEND_DIR:-}"

if [[ -z "$PROJECT_PATH" ]]; then
  PROJECT_PATH="$(find "$MAC_SRC_DIR" -maxdepth 4 -name "*.xcodeproj" | sort | head -n 1)"
fi
PROJECT_DIR="$(dirname "$PROJECT_PATH")"
if [[ -z "$TARGET_DIR" ]]; then
  TARGET_DIR="$(find "$PROJECT_DIR" -maxdepth 4 -type d -name EmbeddedBackend | head -n 1)"
fi
mkdir -p "$DIST_PATH" "$WORK_PATH" "$SPEC_PATH" "$TARGET_DIR"

"$PYTHON_BIN" -m pip install -q pyinstaller

"$PYTHON_BIN" -m PyInstaller \
  --noconfirm --clean --onefile \
  --name "$BACKEND_BIN_NAME" \
  --distpath "$DIST_PATH" \
  --workpath "$WORK_PATH" \
  --specpath "$SPEC_PATH" \
  --add-data "$WEB_SRC_DIR/app.py:." \
  --add-data "$WEB_SRC_DIR/<module_dir>:<module_dir>" \
  "$WEB_SRC_DIR/backend_embedded_launcher.py"

cp "$DIST_PATH/$BACKEND_BIN_NAME" "$TARGET_DIR/$BACKEND_BIN_NAME"
chmod +x "$TARGET_DIR/$BACKEND_BIN_NAME"

SwiftUI Host Requirements

  • Use @Observable host object.
  • Compute serverURL from host/port + query items.
  • Start backend once on appear; stop on disappear.
  • Render backend URL in WKWebView.
  • Retry provisional load failure after short delay.
  • Keep debug controls behind #if DEBUG.
  • Add toolbar Help action that opens a bundled local help.html in a sheet/webview.

Settings Sync Contract

  • Shared path: ~/.<app>/settings.json
  • Normalize every field on web and native sides.
  • Load shared file before app launch.
  • Push normalized fields as query params when launching/reloading webview.
  • Persist setup-sheet changes back to shared file.
  • Keep a legacy fallback path for migration when needed.

Packaging Commands

  • Build app:
./scripts/build_selfcontained_mac_app.sh
  • Create DMG:
APP_BUNDLE_PATH="dist-mac/<timestamp>/<AppName>Mac.app" ./scripts/create_installer_dmg.sh

Expected DMG output:

build/dmg/<AppName>-<timestamp>.dmg

Git Ignore Baseline

build/
*.dmg
rw.*.dmg

Verification Checklist

  • No external browser window opens.
  • App starts with embedded backend from app resources.
  • WKWebView loads local URL.
  • Settings persist across relaunch and remain in sync.
  • Native Help popup renders bundled content.
  • Web-only run has sidebar help fallback.
  • DMG installs and runs on a second machine.
  • DMG is produced under build/dmg/ and repo root stays clean.