diff --git a/demo/content/music/- And we watched as the product was manufa (Remix) (Remastered x2) (Remix).mp3 b/demo/content/music/- And we watched as the product was manufa (Remix) (Remastered x2) (Remix).mp3 new file mode 100644 index 00000000..3ee52083 Binary files /dev/null and b/demo/content/music/- And we watched as the product was manufa (Remix) (Remastered x2) (Remix).mp3 differ diff --git a/demo/content/music/1 - Govcucks.wav b/demo/content/music/1 - Govcucks.wav new file mode 100644 index 00000000..09a6a690 Binary files /dev/null and b/demo/content/music/1 - Govcucks.wav differ diff --git a/demo/content/music/All the leaves are brown.mp3 b/demo/content/music/All the leaves are brown.mp3 new file mode 100644 index 00000000..c64cc3a4 Binary files /dev/null and b/demo/content/music/All the leaves are brown.mp3 differ diff --git a/demo/content/music/An Exploited Substrate.mp3 b/demo/content/music/An Exploited Substrate.mp3 new file mode 100644 index 00000000..27d7f75f Binary files /dev/null and b/demo/content/music/An Exploited Substrate.mp3 differ diff --git a/demo/content/music/Architects of Tomorrow.wav b/demo/content/music/Architects of Tomorrow.wav new file mode 100644 index 00000000..0161a29c Binary files /dev/null and b/demo/content/music/Architects of Tomorrow.wav differ diff --git a/demo/content/music/Bad Actors Reveal.mp3 b/demo/content/music/Bad Actors Reveal.mp3 new file mode 100644 index 00000000..069f4e05 Binary files /dev/null and b/demo/content/music/Bad Actors Reveal.mp3 differ diff --git a/demo/content/music/Bitcoin Salad.MP3 b/demo/content/music/Bitcoin Salad.MP3 new file mode 100644 index 00000000..0a5bea9a Binary files /dev/null and b/demo/content/music/Bitcoin Salad.MP3 differ diff --git a/demo/content/music/Builders, not talkers (Remastered).mp3 b/demo/content/music/Builders, not talkers (Remastered).mp3 new file mode 100644 index 00000000..bafdc514 Binary files /dev/null and b/demo/content/music/Builders, not talkers (Remastered).mp3 differ diff --git a/demo/content/music/Builders.MP3 b/demo/content/music/Builders.MP3 new file mode 100644 index 00000000..2ad5f6fe Binary files /dev/null and b/demo/content/music/Builders.MP3 differ diff --git a/demo/content/music/Exploted Substrate.MP3 b/demo/content/music/Exploted Substrate.MP3 new file mode 100644 index 00000000..228c90cc Binary files /dev/null and b/demo/content/music/Exploted Substrate.MP3 differ diff --git a/demo/content/music/FTFF (Final 2 Gained).MP3 b/demo/content/music/FTFF (Final 2 Gained).MP3 new file mode 100644 index 00000000..0d090f1e Binary files /dev/null and b/demo/content/music/FTFF (Final 2 Gained).MP3 differ diff --git a/demo/content/music/Gay Eye (Final).MP3 b/demo/content/music/Gay Eye (Final).MP3 new file mode 100644 index 00000000..cfaa4e32 Binary files /dev/null and b/demo/content/music/Gay Eye (Final).MP3 differ diff --git a/demo/content/music/Hootcoiner.mp3 b/demo/content/music/Hootcoiner.mp3 new file mode 100644 index 00000000..6fbd1dae Binary files /dev/null and b/demo/content/music/Hootcoiner.mp3 differ diff --git a/demo/content/music/Horseman of Technocracy.MP3 b/demo/content/music/Horseman of Technocracy.MP3 new file mode 100644 index 00000000..c5a508b0 Binary files /dev/null and b/demo/content/music/Horseman of Technocracy.MP3 differ diff --git a/demo/content/music/In Koyote We Trust (final).MP3 b/demo/content/music/In Koyote We Trust (final).MP3 new file mode 100644 index 00000000..09a123ae Binary files /dev/null and b/demo/content/music/In Koyote We Trust (final).MP3 differ diff --git a/demo/content/music/Inverse Dylan (Remix).mp3 b/demo/content/music/Inverse Dylan (Remix).mp3 new file mode 100644 index 00000000..6fc00b1f Binary files /dev/null and b/demo/content/music/Inverse Dylan (Remix).mp3 differ diff --git a/demo/content/music/Max Says Build.MP3 b/demo/content/music/Max Says Build.MP3 new file mode 100644 index 00000000..8478bd5c Binary files /dev/null and b/demo/content/music/Max Says Build.MP3 differ diff --git a/demo/content/music/SMRI.mp3 b/demo/content/music/SMRI.mp3 new file mode 100644 index 00000000..3f9c667b Binary files /dev/null and b/demo/content/music/SMRI.mp3 differ diff --git a/demo/content/music/Sats or Shackles.mp3 b/demo/content/music/Sats or Shackles.mp3 new file mode 100644 index 00000000..b258fc56 Binary files /dev/null and b/demo/content/music/Sats or Shackles.mp3 differ diff --git a/demo/content/music/Shadrap.mp3 b/demo/content/music/Shadrap.mp3 new file mode 100644 index 00000000..071f8e9f Binary files /dev/null and b/demo/content/music/Shadrap.mp3 differ diff --git a/demo/content/music/Sound money.MP3 b/demo/content/music/Sound money.MP3 new file mode 100644 index 00000000..69958a79 Binary files /dev/null and b/demo/content/music/Sound money.MP3 differ diff --git a/demo/content/music/Stacks or Shackles.MP3 b/demo/content/music/Stacks or Shackles.MP3 new file mode 100644 index 00000000..82afc80b Binary files /dev/null and b/demo/content/music/Stacks or Shackles.MP3 differ diff --git a/demo/content/music/The Four Horseman of Technocracy.mp3 b/demo/content/music/The Four Horseman of Technocracy.mp3 new file mode 100644 index 00000000..506cf3d0 Binary files /dev/null and b/demo/content/music/The Four Horseman of Technocracy.mp3 differ diff --git a/demo/content/music/The Wehrman.mp3 b/demo/content/music/The Wehrman.mp3 new file mode 100644 index 00000000..736a2d9a Binary files /dev/null and b/demo/content/music/The Wehrman.mp3 differ diff --git a/demo/content/music/Wash the fucking dishes.mp3 b/demo/content/music/Wash the fucking dishes.mp3 new file mode 100644 index 00000000..5b80d092 Binary files /dev/null and b/demo/content/music/Wash the fucking dishes.mp3 differ diff --git a/demo/content/music/Winning is Invisible.MP3 b/demo/content/music/Winning is Invisible.MP3 new file mode 100644 index 00000000..bd5fdf19 Binary files /dev/null and b/demo/content/music/Winning is Invisible.MP3 differ diff --git a/demo/content/music/death is a gift.mp3 b/demo/content/music/death is a gift.mp3 new file mode 100644 index 00000000..8297446f Binary files /dev/null and b/demo/content/music/death is a gift.mp3 differ diff --git a/demo/content/music/decentrealisation.mp3 b/demo/content/music/decentrealisation.mp3 new file mode 100644 index 00000000..b8792d2a Binary files /dev/null and b/demo/content/music/decentrealisation.mp3 differ diff --git a/demo/content/music/neo-morality.mp3 b/demo/content/music/neo-morality.mp3 new file mode 100644 index 00000000..18c708f4 Binary files /dev/null and b/demo/content/music/neo-morality.mp3 differ diff --git a/loop/plan.md b/loop/plan.md index 75ab3550..f98645d7 100644 --- a/loop/plan.md +++ b/loop/plan.md @@ -1,102 +1,337 @@ -# Alpha Release Hardening Plan — Overnight Automation +# 2-Year Production Roadmap — Archipelago v1.0 -**Goal**: Make Archipelago flawless for alpha testers installing on their own hardware. -**Priority**: Onboarding perfection > App install reliability > AIUI hardening > UI polish -**Rule**: No new features. No design changes (except smoothing transitions). Harden everything. +**Goal**: Take Archipelago from developer preview to a flawless, mass-market Bitcoin Node OS. Every app installs perfectly, every service runs reliably, every interaction is polished and intuitive — on desktop and mobile. + +**Timeline**: March 2026 → March 2028 (8 quarters) +**Method**: Quarterly phases, each building on the last. Deploy and verify after every task. --- -## Phase 1: Onboarding Flow (Critical Path) +## Q1 2026 (Mar–May): Foundation Hardening -- [x] **OB-001** — fix(onboarding): convert "Choose Your Path" screen (`neode-ui/src/views/OnboardingPath.vue`) from a selection screen to an informative screen. Keep the exact same 6 cards (Self Sovereignty, Community Commerce, Sovereign Projects, Data Transmitter, Hoster, Sovereign AI) with their current design, but remove the toggle/selection behavior. Remove the `toggleOption()` click handler and `--selected` class binding. Change heading from "Choose Your Path" to "Your Node, Your Possibilities". Change subtitle to "Archipelago gives you the tools to build your sovereign digital life. All of these capabilities are available from your dashboard." Remove "Skip" button — only keep "Continue" which navigates to `/onboarding/did`. The cards should be read-only informational cards, not buttons. Deploy and verify. +### Phase 1A: App Store Reliability — Every App Installs Without Fail -- [x] **OB-002** — fix(onboarding): harden the "Choose Your Setup" screen (`neode-ui/src/views/OnboardingOptions.vue`) — this is the Fresh Start / Restore / Connect screen. For alpha, only "Fresh Start" should work — gray out and disable "Restore Backup" and "Connect Existing" with a "(Coming Soon)" label. Make "Fresh Start" auto-selected on mount so users don't have to click before pressing Continue. Ensure `completeOnboarding()` is called reliably (currently it might fail silently and user gets stuck). Deploy and verify. +- [x] **APP-101** — fix(marketplace): audit and fix all 24 marketplace app install flows. For each app in `getCuratedAppList()` in `neode-ui/src/views/Marketplace.vue` (bitcoin-knots, electrs, btcpay-server, lnd, mempool, homeassistant, grafana, searxng, ollama, onlyoffice, penpot, nextcloud, vaultwarden, jellyfin, photoprism, immich, filebrowser, nginx-proxy-manager, portainer, uptime-kuma, tailscale, fedimint, indeedhub), verify each one: (1) marketplace card renders correctly with icon, (2) clicking Install triggers `package.install` RPC, (3) container pulls and creates successfully, (4) container starts on the correct ports per `apps/PORTS.md`, (5) status shows "Running" in My Apps. Fix any broken apps. Deploy with `./scripts/deploy-to-target.sh --live`. Test each app at http://192.168.1.228. -- [x] **OB-003** — fix(onboarding): harden the DID retrieval step (`neode-ui/src/views/OnboardingDid.vue`). If the server is not reachable (502/503/timeout), show a clear message "Connecting to your server..." with a retry button instead of the fallback "did:key:z6Mk... (connect to server)" text. Auto-fetch the DID on mount (don't wait for button click — the "Retrieve DID" button adds friction). If fetch succeeds, auto-advance after 2 seconds with a "DID retrieved, continuing..." message. Keep Skip button. +- [ ] **APP-102** — fix(apps): ensure iframe vs new-tab behavior is correct for all apps. In `neode-ui/src/stores/appLauncher.ts`, verify `mustOpenInNewTab()` includes all apps that set `X-Frame-Options: DENY/SAMEORIGIN`. Currently covers BTCPay (23000), Home Assistant (8123), Nextcloud (8085), Immich (2283). Test each running app by clicking "Open" in AppDetails.vue — iframe apps must load inside the overlay, new-tab apps must open in a fresh browser tab. If any app fails to load in iframe, either fix the nginx proxy to strip X-Frame-Options or add it to `mustOpenInNewTab()`. Deploy and verify each app. -- [x] **OB-004** — fix(onboarding): harden the Backup step (`neode-ui/src/views/OnboardingBackup.vue`). Ensure the `rpcClient.createBackup()` call works on a fresh install. If it fails, show a helpful error message. Make the download work on mobile (some browsers block `a.click()` programmatic downloads). Test the full backup/download flow. Deploy and verify. +- [ ] **APP-103** — fix(apps): verify all PORT_TO_PROXY mappings in appLauncher.ts match nginx config. Cross-reference every entry in `PORT_TO_PROXY` in `neode-ui/src/stores/appLauncher.ts` with the actual nginx location blocks in `image-recipe/configs/nginx-archipelago.conf` and `image-recipe/configs/snippets/archipelago-https-app-proxies.conf`. Any missing nginx proxy blocks must be added. Any port mismatches must be corrected. Deploy nginx config and verify each app loads via its proxy path. -- [x] **OB-005** — fix(onboarding): harden the Verify step (`neode-ui/src/views/OnboardingVerify.vue`). The `signChallenge()` call must work on a fresh server with a new identity. If it fails, allow user to retry or skip gracefully. Ensure `completeOnboarding()` is called on both proceed and skip paths (already done, but verify). Deploy and verify. +- [ ] **APP-104** — fix(deploy): ensure first-boot-containers.sh creates every marketplace app container. Compare the apps listed in `scripts/first-boot-containers.sh` with `scripts/deploy-to-target.sh`. Any app that deploy creates but first-boot doesn't must be added to first-boot. This ensures fresh ISO installs have all containers ready. -- [x] **OB-006** — fix(onboarding): verify the complete onboarding flow end-to-end. Clear onboarding state on server (`rpcClient.resetOnboarding()` if it exists, or clear localStorage `neode_onboarding_complete`). Walk through every step: Intro → Path (informative) → DID → Backup → Verify → Done → Login. Each transition must be smooth with the 3D depth effect. No JS errors in console. Deploy and verify. +- [ ] **APP-105** — fix(backend): verify get_app_config() handles all 24 apps. In `core/archipelago/src/api/rpc/package.rs`, check `get_app_config()` returns correct ports, volumes, env vars, and custom args for every marketplace app. Any app missing its config will fail to install. Add missing configs. -## Phase 2: First Login & Password Setup +- [ ] **APP-106** — fix(backend): verify get_app_metadata() for all 24 apps. In `core/archipelago/src/container/docker_packages.rs`, check `get_app_metadata()` returns correct title, description, icon path, and repo URL for every marketplace app. Fix missing or incorrect entries. -- [x] **LOGIN-001** — fix(login): verify the login flow on a fresh install. The first user must be able to set a password (setup mode). After setting password, redirect to login. After login, redirect to dashboard. Test: clear all state, visit http://192.168.1.228, complete onboarding, set password, login. The startup progress bar must appear only when the server is genuinely starting (not on normal page loads). Deploy and verify. +### Phase 1B: App Dependencies — Bitcoin, Lightning, Fedimint Chains -- [x] **LOGIN-002** — fix(login): harden the RootRedirect component (`neode-ui/src/views/RootRedirect.vue`). On a fresh install, root `/` must redirect to `/onboarding/intro`. After onboarding, root must redirect to `/login`. After login, must redirect to `/dashboard`. Test all three states. No infinite redirect loops. Deploy and verify. +- [ ] **DEP-101** — fix(backend): implement robust dependency checking for all apps. In `core/archipelago/src/api/rpc/package.rs`, ensure dependency checks work: Electrs requires Bitcoin Knots running, LND requires Bitcoin Knots running, BTCPay requires LND running, Mempool requires Bitcoin Knots + Electrs. When installing an app with unmet dependencies, the UI should either auto-install dependencies or show a clear message: "Bitcoin Knots must be installed and running first." Deploy and verify by trying to install Electrs without Bitcoin. -## Phase 3: App Installation Reliability +- [ ] **DEP-102** — fix(ui): show dependency status in MarketplaceAppDetails.vue. When viewing an app that has dependencies, show a "Requirements" section listing each dependency with a green checkmark (installed & running), yellow warning (installed but stopped), or red X (not installed). Add an "Install All Requirements" button that queues dependency installations in order. This lives in `neode-ui/src/views/MarketplaceAppDetails.vue`. -- [x] **APP-001** — fix(apps): verify that the Marketplace loads all available apps from manifests in `apps/*/manifest.yml`. Each app should have: name, description, icon, version. Test the marketplace page loads without errors. Deploy and verify. +- [ ] **DEP-103** — feat(fedimint): integrate Fedimint Guardian + Gateway as paired services. Fedimint currently runs as a single container (fedimintd). Add Fedimint Gateway as a companion service that runs alongside the Guardian. In `scripts/deploy-to-target.sh`, when creating fedimint, also create `fedimint-gateway` container using `fedimint/gatewayd` image. Configure the gateway to auto-connect to the guardian. In the Marketplace, show Fedimint as one app that runs both services. The UI should show both Guardian and Gateway status. -- [x] **APP-002** — fix(apps): test installing Bitcoin Knots (the most critical app). The install flow is: click Install → pull image → create container → start → show running state. Verify each step works. If image pull fails (no internet), show a clear error. If container fails to start, show logs. After successful install, the app should appear in "My Apps" with correct status. Deploy and verify. +- [ ] **DEP-104** — feat(fedimint): auto-configure Fedimint Gateway to use LND. The Fedimint Gateway needs a Lightning backend. When both LND and Fedimint are installed, auto-configure the gateway to use LND's gRPC endpoint. In `core/archipelago/src/api/rpc/package.rs`, add Fedimint Gateway config that reads LND's tls.cert and admin.macaroon from the LND data volume. The user should only need to open lightning channels — everything else should be automatic. -- [x] **APP-003** — fix(apps): test installing at least 3 more apps from the marketplace (e.g., Mempool, LND, Electrs). Verify each installs and shows correct status. If any app fails, fix the manifest or backend logic. Ensure app dependencies are resolved (e.g., LND depends on Bitcoin). Deploy and verify. +- [ ] **DEP-105** — feat(ui): lightning channel management interface. Create `neode-ui/src/views/apps/LightningChannels.vue` accessible from the LND app detail page. Show: (1) list of open channels with capacity bars, (2) "Open Channel" button with peer URI input and amount, (3) channel status (pending open/close, active, inactive), (4) total inbound/outbound liquidity summary. Use existing RPC to call LND's REST API through the backend proxy. This is critical for Fedimint Gateway to be useful. -- [x] **APP-004** — fix(apps): verify app uninstall works cleanly. Install an app, verify it runs, uninstall it, verify it's removed from both the UI and the container runtime (`podman ps -a`). No orphaned containers or data. Deploy and verify. +### Phase 1C: Animation & UI Polish -- [x] **APP-005** — fix(apps): verify app detail pages load correctly. Click into an installed app → should show: status, version, logs (if available), open button (if applicable). No JS errors, no blank pages. The iframe for web-UI apps must load with correct port. Deploy and verify. +- [ ] **ANIM-101** — fix(css): audit and improve all transition animations in style.css. In `neode-ui/src/style.css`, review every `transition` property. Standardize: (1) hover lifts use `transform: translateY(-2px)` with `transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)`, (2) active presses use `translateY(1px)`, (3) color transitions use `transition: color 0.2s ease, background-color 0.2s ease`, (4) modal/overlay entrances use `transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)`. Replace all `transition: all 0.3s ease` with specific properties to avoid animating layout properties. Deploy and verify animations feel smooth. -## Phase 4: AIUI Chat Hardening +- [ ] **ANIM-102** — fix(ui): add smooth page transitions between routes. In `neode-ui/src/views/Dashboard.vue`, wrap `` in a `` component with `name="page"`. In `style.css`, add: `.page-enter-active, .page-leave-active { transition: opacity 0.2s ease, transform 0.2s ease; }` `.page-enter-from { opacity: 0; transform: translateY(8px); }` `.page-leave-to { opacity: 0; }`. This gives every page navigation a subtle fade-up entrance. Deploy and verify navigation feels smooth. -- [x] **AIUI-001** — fix(aiui): verify the AIUI chat loads in the dashboard. Navigate to `/dashboard/chat`. The iframe must load AIUI from `/aiui/`. Check: no 404s, no CORS errors, no blank white screen. The context broker must be initialized. Deploy and verify. +- [ ] **ANIM-103** — fix(ui): add staggered entrance animations for card grids. In views that display card grids (Apps.vue, Marketplace.vue, Home.vue, Web5.vue), add staggered entrance animations so cards appear one after another with a 50ms delay. Use CSS `animation-delay` with `nth-child()` or Vue's ``. The effect should be subtle — cards fade in and slide up slightly. Deploy and verify. -- [x] **AIUI-002** — fix(aiui): verify the Claude proxy is running and responds. Test: `curl -X POST http://192.168.1.228/aiui/api/claude/v1/messages -H 'Content-Type: application/json' -d '{"model":"haiku","messages":[{"role":"user","content":"hello"}],"stream":false}'` (with session cookie). Should get a valid response or proper auth error. If proxy is down, restart `claude-proxy` service. Deploy and verify. +- [ ] **ANIM-104** — fix(ui): smooth loading state transitions. In all views that have loading states, ensure the transition from loading to loaded is animated — not an instant swap. Use Vue's `` with `mode="out-in"` around loading/content states. The loading spinner should fade out as the content fades in. Deploy and verify on Apps, Marketplace, Server, and Home views. -- [x] **AIUI-003** — fix(aiui): verify the API key switcher works. Open AIUI settings → Chat tab → enable "Use my own API key" → paste the test key `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` → send a message → verify response comes back. Then disable the toggle → verify it falls back to server OAuth. Deploy and verify. +- [ ] **ANIM-105** — fix(ui): polish the app launcher overlay animation. In `neode-ui/src/components/AppLauncherOverlay.vue`, ensure the overlay slides up smoothly when opening an app. Add a subtle backdrop blur transition. The iframe should have a loading indicator that fades out when the app loads. The close animation should slide down. Use `will-change: transform` for GPU acceleration. Deploy and verify. -- [x] **AIUI-004** — fix(aiui): verify that the context broker surfaces node data to AIUI. Enable all AI permissions in Settings → AI Data Access. Then ask AIUI "what apps are installed?" or "what's my server status?". The response should include real data from the node (via postMessage → contextBroker → stores/RPC). If it doesn't, debug the postMessage flow. Deploy and verify. +### Phase 1D: Mobile Responsiveness -- [x] **AIUI-005** — fix(aiui): verify that message send, reply, and regenerate all work without the "empty content" API error. Send multiple messages in a row. Use reply on a specific message. Use regenerate. None should produce "messages.N: user messages must have non-empty content" errors. Deploy and verify. +- [ ] **MOB-101** — fix(ui): audit and fix all views at 375px (iPhone SE) width. Test every view at 375px: Login, Dashboard sidebar, Home, Apps, Marketplace, AppDetails, MarketplaceAppDetails, Settings, Web5, Cloud, Server, Chat. Fix: horizontal overflow, overlapping elements, text truncation, buttons too small to tap (min 44px touch target), broken grid layouts. Add or fix responsive Tailwind classes in `style.css`. Deploy and verify. -## Phase 5: Dashboard & UI Polish +- [ ] **MOB-102** — fix(ui): optimize sidebar navigation for mobile. The Dashboard sidebar should collapse to a bottom tab bar on mobile (< 768px). Show icons only with labels below. The mode switcher should be accessible from Settings on mobile. Ensure the sidebar doesn't overlap content on mobile. Deploy and verify. -- [x] **UI-001** — fix(ui): verify all dashboard nav items work: Home, My Apps, Marketplace, Cloud, Server, Web5, Settings, Chat. Each must load without errors. No blank pages, no console errors. The sidebar navigation must highlight the active item. Deploy and verify. - -- [x] **UI-002** — fix(ui): verify the Home dashboard shows correct data: server status (online/offline), uptime, disk usage, memory, CPU. If metrics RPC fails, show placeholder data with "Connecting..." state instead of errors. Deploy and verify. - -- [x] **UI-003** — fix(ui): verify the Server page loads and shows system info. Test all sections: system overview, services list, network info. No JS errors. Deploy and verify. - -- [x] **UI-004** — fix(ui): verify the Settings page loads all sections: General, Security (password change), AI Data Access, Tor, About. No JS errors. The AI Data Access toggles must persist between page loads. Deploy and verify. - -- [x] **UI-005** — fix(ui): test WebSocket connection stability. After login, the WebSocket at `/ws` should connect and stay connected. If it disconnects, verify auto-reconnect works. Check: no repeated "WebSocket disconnected" errors in console. Deploy and verify. - -- [x] **UI-006** — fix(ui): ensure all page transitions are smooth. Navigate between all dashboard pages. The 3D depth transitions should be fluid without flicker or layout jumps. If any transition stutters, optimize by adding `will-change` or reducing transition complexity. Deploy and verify. - -## Phase 5b: AIUI Security Hardening (from research audit) - -- [x] **SEC-001** — fix(aiui): add confirmation dialog for AIUI app installs. In `neode-ui/src/services/contextBroker.ts`, the `install-app` action currently fires without user confirmation. Change it to emit a custom event (`window.dispatchEvent(new CustomEvent('aiui:install-request', { detail: { appId, version, url } }))`) that the Dashboard UI can intercept with a confirmation modal. Only proceed with `appStore.installPackage()` after user confirms. This prevents AIUI from silently installing apps. - -- [x] **SEC-002** — fix(aiui): add file path whitelist to AIUI file access. In `neode-ui/src/services/contextBroker.ts`, the `read-file` action currently allows reading any path. Add a whitelist of allowed directories (e.g., `/var/lib/archipelago/`, `/var/log/`) and reject paths containing sensitive patterns (`id_rsa`, `private`, `secret`, `password`, `seed`, `.env`, `wallet`). This prevents AIUI from exfiltrating secrets. - -- [x] **SEC-003** — fix(aiui): add log redaction for container logs. In the context broker's log handler, redact sensitive patterns from container logs before sending to AIUI: RPC passwords, private keys (hex strings > 32 chars), API tokens, and macaroon values. - -- [x] **SEC-004** — fix(auth): add `Secure` flag to session cookie in production. In `core/archipelago/src/api/rpc/mod.rs`, add `; Secure` to the `Set-Cookie` header when `dev_mode` is false. This prevents the session cookie from being transmitted over plain HTTP in production. - -## Phase 6: Alpha ISO Build - -- [x] **ISO-001** — fix(iso): sync all current changes to the dev server. Run full deploy: `./scripts/deploy-to-target.sh --live`. Verify everything works on http://192.168.1.228. Then SSH to the server and run the ISO build: `cd ~/archy/image-recipe && sudo DEV_SERVER=archipelago@localhost ./build-auto-installer-iso.sh`. The ISO must build successfully and be saved to `results/`. Report the ISO path and size. - -- [x] **ISO-002** — fix(iso): verify the ISO image configs include all latest changes. Check that `image-recipe/configs/` has up-to-date: `archipelago.service`, `nginx-archipelago.conf`. If they differ from the live server, update them. The ISO must produce a bootable system identical to the current live server. +- [ ] **MOB-103** — fix(ui): optimize app launcher overlay for mobile. The app iframe launcher should be full-screen on mobile with a sticky top bar (app title + close + open-in-new-tab). On desktop, maintain the current overlay style. Deploy and verify apps are usable on mobile. --- -## Post-Completion Verification +## Q2 2026 (Jun–Aug): Identity & Onboarding -After all tasks are done, run a full verification: +### Phase 2A: Multi-Identity System + +- [ ] **ID-101** — feat(backend): implement identity manager with multiple DIDs. Create `core/archipelago/src/identity/mod.rs` with: (1) `IdentityManager` struct that stores multiple identities in `/var/lib/archipelago/identity/`, (2) each identity has an Ed25519 keypair, a DID, a display name, and a purpose tag (personal, business, anonymous), (3) the first identity is created during onboarding, (4) RPC endpoints: `identity.list`, `identity.create`, `identity.delete`, `identity.get`, `identity.set-default`. Store identities encrypted using the node's master key. Build on server and deploy. + +- [ ] **ID-102** — feat(backend): implement identity signing service. Add `identity.sign` and `identity.verify` RPC endpoints. `identity.sign` takes a DID id and a message, returns a detached Ed25519 signature. `identity.verify` takes a DID, message, and signature, returns boolean. This enables apps to request signatures from the user's chosen identity. Build on server and deploy. + +- [ ] **ID-103** — feat(ui): identity management view. Create a new "Identity" section in the Web5 view (replace the hidden `v-if="false"` DID section at line 429 of `Web5.vue`). Show: (1) list of all identities with name, DID (truncated), purpose badge, (2) "Create Identity" button that opens a modal with name + purpose selector, (3) each identity card has Copy DID, Set Default, Delete actions, (4) the default identity shows a star badge. Wire to the backend RPC endpoints from ID-101. Deploy and verify. + +- [ ] **ID-104** — feat(ui): identity picker for service connections. Create a reusable `` component that shows a dropdown of the user's identities with their names and truncated DIDs. When a service (like Indeehub) needs a DID, it calls this component to let the user choose which identity to use. The selected identity's DID and signing capability are then passed to the service. + +- [ ] **ID-105** — feat(backend): Nostr identity bridge. Each identity can optionally have an associated Nostr keypair (secp256k1). Add `identity.create-nostr-key` RPC that generates a Nostr keypair linked to an identity. Add `identity.nostr-sign` for NIP-01 event signing. This bridges the DID world with Nostr. The user's Nostr pubkey is derivable from their identity. Build on server and deploy. + +- [ ] **ID-106** — feat(apps): Indeehub identity integration. When opening Indeehub, pass the user's selected identity DID via the iframe URL or postMessage. Indeehub should recognize the user's sovereign identity without requiring account creation. Implement the postMessage protocol: parent sends `{ type: 'archipelago:identity', did: '...', signature: '...' }`, Indeehub responds with `{ type: 'archipelago:identity:ack' }`. Deploy and verify Indeehub recognizes the user. + +### Phase 2B: Onboarding Flow Polish + +- [ ] **ONB-101** — fix(ui): polish onboarding intro animation. In `neode-ui/src/views/OnboardingIntro.vue`, add a cinematic entrance: the Archipelago logo fades in with a subtle scale (0.95 → 1.0), followed by the tagline sliding up, then the "Get Started" button fading in. Total duration: 2 seconds. Use CSS keyframe animations. Deploy and verify. + +- [ ] **ONB-102** — fix(ui): improve onboarding DID step UX. In `OnboardingDid.vue`, when the backend generates the DID, show a brief animation of key generation (spinning lock icon → checkmark). Display the DID in a styled card with a copy button. Explain in plain language: "This is your sovereign digital identity. It proves you are you, without any company in the middle." Deploy and verify. + +- [ ] **ONB-103** — fix(ui): add identity purpose selection to onboarding. After DID creation in onboarding, add a step where the user names their first identity (default: "Personal") and optionally selects a purpose (Personal, Business, Anonymous). This feeds into the multi-identity system from ID-101. Deploy and verify. + +- [ ] **ONB-104** — fix(ui): smooth transition between onboarding steps. Add a horizontal slide transition between onboarding steps — swiping left to advance, right to go back. Use `` with `name="slide"` and direction-aware classes. Deploy and verify the flow feels like swiping through cards. + +--- + +## Q3 2026 (Sep–Nov): Network & Node Discovery + +### Phase 3A: Node Overlay Network + +- [ ] **NET-101** — feat(backend): implement node visibility signaling. Create `core/archipelago/src/network/overlay.rs` with: (1) a `NodeVisibility` enum (Hidden, Discoverable, Public), (2) RPC endpoints `network.set-visibility` and `network.get-visibility`, (3) when set to Discoverable, the node publishes a Nostr NIP-33 replaceable event (kind 30078, tag `d:archipelago-node`) with its onion address and public DID, (4) when set to Hidden, the event is deleted. This uses the existing Nostr discovery code in `core/archipelago/src/nostr_discovery.rs`. Build on server and deploy. + +- [ ] **NET-102** — feat(backend): implement connection request protocol. Add RPC endpoints: `network.request-connection` (sends a connection request to a peer's onion address over Tor), `network.list-requests` (shows pending incoming requests), `network.accept-request` (adds peer to trusted list), `network.reject-request`. Connection requests are sent as encrypted Nostr DMs (NIP-04) containing the sender's DID and onion address. Build on server and deploy. + +- [ ] **NET-103** — feat(ui): node visibility controls in Web5 view. In the Web5 view, add a "Node Visibility" card (replace or augment the existing Connected Nodes section). Show: (1) current visibility status (Hidden/Discoverable/Public), (2) toggle to change visibility, (3) when Discoverable, show the node's onion address, (4) warning: "Making your node discoverable lets other Archipelago users find and connect with you." Wire to NET-101 RPCs. Deploy and verify. + +- [ ] **NET-104** — feat(ui): connection request management. In the Web5 view, add a "Connection Requests" tab to the Connected Nodes section. Show: (1) incoming requests with sender DID and timestamp, (2) Accept/Reject buttons, (3) notification badge on the Web5 sidebar icon when requests are pending. Wire to NET-102 RPCs. Deploy and verify. + +- [ ] **NET-105** — feat(backend): implement peer health monitoring. Add a background task that periodically (every 5 minutes) checks if connected peers are reachable over Tor. Update peer status in the database. Send WebSocket events when peer status changes. The existing `rpcClient.checkPeerReachable()` in Web5.vue already calls this — ensure the backend implementation is robust with timeouts. Build on server and deploy. + +### Phase 3B: Tor Services Management + +- [ ] **TOR-101** — feat(backend): implement Tor hidden service management RPC. Create RPC endpoints: `tor.list-services` (returns all configured hidden services with their .onion addresses), `tor.create-service` (creates a new hidden service for a given local port), `tor.delete-service`, `tor.get-onion-address`. Read from `/var/lib/archipelago/tor/` directory structure. Currently Tor setup is hardcoded in deploy script — make it dynamic. Build on server and deploy. + +- [ ] **TOR-102** — feat(ui): Tor services management in Settings or Web5. Add a "Tor Services" section showing: (1) list of all hidden services with their .onion addresses and what app they expose, (2) toggle to enable/disable Tor for each service, (3) "Broadcast my services over Tor" master toggle, (4) copy .onion address button for each service. Wire to TOR-101 RPCs. Deploy and verify. + +- [ ] **TOR-103** — fix(deploy): make Tor hidden service creation dynamic. Refactor `scripts/deploy-to-target.sh` Tor section (lines 471-530) to read from a config file (`/var/lib/archipelago/tor/services.json`) instead of hardcoding services. When an app is installed that supports Tor, automatically add a hidden service entry. When uninstalled, remove it. Rebuild torrc from the config file and restart the Tor container. Deploy and verify. + +- [ ] **TOR-104** — feat(backend): Tor-based content serving. When a peer accesses your node over Tor, serve only the content you've explicitly made available. Create `core/archipelago/src/network/content_server.rs` with: (1) a list of shared content items (files, streams), (2) access control per item (free, paid via ecash), (3) a lightweight HTTP handler that serves content to authenticated peers. This is the foundation for content streaming. Build on server and deploy. + +--- + +## Q4 2026 (Dec–Feb 2027): Ecash & Content Economy + +### Phase 4A: Ecash Integration + +- [ ] **ECASH-101** — feat(backend): implement Cashu ecash wallet. Create `core/archipelago/src/wallet/ecash.rs` with: (1) Cashu wallet client that connects to the local Fedimint mint, (2) RPC endpoints: `wallet.ecash-balance`, `wallet.ecash-mint` (create ecash tokens from Lightning), `wallet.ecash-melt` (redeem ecash to Lightning), `wallet.ecash-send` (create ecash token for peer), `wallet.ecash-receive` (accept ecash token from peer). Use the Cashu protocol for interoperability. Build on server and deploy. + +- [ ] **ECASH-102** — feat(ui): ecash wallet in Web5 view. Replace the dummy "Web5 Wallet" card in Web5.vue (lines 221-268) with a real ecash wallet UI. Show: (1) ecash balance in sats, (2) Mint button (Lightning → ecash), (3) Melt button (ecash → Lightning), (4) Send button (generates ecash token string), (5) Receive button (paste ecash token), (6) transaction history. Wire to ECASH-101 RPCs. Deploy and verify. + +- [ ] **ECASH-103** — feat(backend): implement pay-per-access content gating. Extend the content server from TOR-104 with ecash payment verification. When content is marked as "paid", the server returns a 402 Payment Required with a Cashu invoice. The requesting peer pays with ecash, receives a receipt token, and includes it in subsequent requests. Implement in `core/archipelago/src/network/content_server.rs`. Build on server and deploy. + +- [ ] **ECASH-104** — feat(ui): content pricing controls. In the content sharing UI (to be built in Phase 4B), add pricing controls: (1) free/paid toggle per content item, (2) price in sats input, (3) "Pay what you want" option with minimum, (4) preview: "Peers will pay X sats to access this." Wire to backend content server config. Deploy and verify. + +### Phase 4B: Content Streaming & File Sharing + +- [ ] **CONTENT-101** — feat(backend): implement content catalog RPC. Create `core/archipelago/src/network/content_catalog.rs` with: (1) `content.list-mine` — list content I'm sharing, (2) `content.add` — add a file or stream to my catalog, (3) `content.remove` — stop sharing, (4) `content.set-pricing` — free or ecash-gated, (5) `content.set-availability` — available to all peers, specific peers, or nobody. Store catalog in `/var/lib/archipelago/content/catalog.json`. Build on server and deploy. + +- [ ] **CONTENT-102** — feat(backend): implement peer content browsing. Add `content.browse-peer` RPC that connects to a peer's onion address over Tor and fetches their content catalog. Returns a list of available items with titles, descriptions, sizes, and prices. The peer's content server (TOR-104) serves the catalog at a well-known endpoint. Build on server and deploy. + +- [ ] **CONTENT-103** — feat(backend): implement content streaming protocol. For media files (video, audio), implement chunked streaming over Tor. The requesting node sends a range request, the serving node streams the content chunk by chunk. For paid content, payment is per-chunk (micropayments via ecash). Use HTTP range requests over the Tor hidden service. Build on server and deploy. + +- [ ] **CONTENT-104** — feat(ui): content sharing dashboard. Create a "Content" tab in the Web5 view. Show: (1) "My Shared Content" — list of files/streams you're sharing with pricing, (2) "Add Content" button — file picker to add from Cloud/FileBrowser, (3) "Browse Peers" — select a connected peer and browse their catalog, (4) download/stream buttons with payment flow for paid content. Deploy and verify. + +- [ ] **CONTENT-105** — feat(ui): content streaming player. When a user clicks to stream video/audio from a peer, open a media player in the app launcher overlay. Show: (1) video/audio player with standard controls, (2) streaming progress indicator, (3) cost tracker (total sats spent on this stream), (4) quality selector if multiple qualities available. Use HTML5 `