docs: trim CLAUDE.md — lean, updated for CI/CD and registry
Some checks failed
Build Archipelago ISO / build-iso (push) Failing after 27m22s
Some checks failed
Build Archipelago ISO / build-iso (push) Failing after 27m22s
Removed duplication with rules/ files, updated infrastructure table (git.tx1138.com, app registry, CI runner, ISO debugging), trimmed from 404 lines to ~120. Security rules kept via reference to rules/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
453
CLAUDE.md
453
CLAUDE.md
@@ -1,403 +1,130 @@
|
||||
# CLAUDE.md — Archipelago (Archy) Project Guide
|
||||
# CLAUDE.md — Archipelago (Archy)
|
||||
|
||||
## Project Overview
|
||||
## Overview
|
||||
|
||||
Archipelago is a **Bitcoin Node OS** — a bootable, self-sovereign personal server you flash to USB, install on hardware, and manage via a web UI. Similar to Umbrel/Start9/RaspiBlitz but custom-built with production-grade security.
|
||||
Archipelago is a **Bitcoin Node OS** — bootable, self-sovereign personal server. Flash to USB, install on hardware, manage via web UI.
|
||||
|
||||
**Stack**: Rust backend + Vue 3 (Composition API) + TypeScript (strict) + Vite 7 + Tailwind CSS + Pinia + Podman
|
||||
**Target OS**: Debian 12 (Bookworm) — x86_64 and ARM64
|
||||
**Current version**: 0.1.0
|
||||
**Stack**: Rust backend + Vue 3 + TypeScript (strict) + Vite 7 + Tailwind + Pinia + Podman on Debian 12
|
||||
**Version**: 0.1.0 | **Target**: x86_64 and ARM64
|
||||
|
||||
---
|
||||
|
||||
## BETA FREEZE — ACTIVE (2026-03-18)
|
||||
## Beta Freeze (2026-03-18)
|
||||
|
||||
**Goal: Ship a flawless beta that works perfectly on every machine we install it on.**
|
||||
**Phase 1: Feature Testing (internal) — WE ARE HERE**
|
||||
|
||||
We are in **beta stabilization mode**. The current feature set is LOCKED. Every session must push toward this goal.
|
||||
Feature set is LOCKED. Only: bug fixes, security hardening, ISO build fixes, UI polish, testing.
|
||||
No new features, no new apps, no new deps, no scope creep.
|
||||
|
||||
### Pipeline
|
||||
|
||||
```
|
||||
PHASE 1: Feature Testing (internal) ← WE ARE HERE
|
||||
↓ Gate: every feature works, bugs fixed, security hardened, ISO verified
|
||||
PHASE 2: User Testing (real users on real hardware we don't control)
|
||||
↓ Gate: user-reported issues resolved, telemetry shows stable fleet
|
||||
PHASE 3: Beta Live (public release)
|
||||
```
|
||||
|
||||
### What IS allowed
|
||||
- Bug fixes for existing features
|
||||
- Security hardening and testing
|
||||
- Beta telemetry / node reporting (TASK-12 — needed for user testing)
|
||||
- UI/layout rearrangements (moving things around, improving flow)
|
||||
- Boot screen completion (FEATURE-4 — already in progress)
|
||||
- Testing all features end-to-end on fresh installs
|
||||
- Performance and reliability improvements to existing code
|
||||
- ISO build hardening
|
||||
|
||||
### What is NOT allowed
|
||||
- New features (watch-only wallet, mesh balance check, etc. are POST-BETA)
|
||||
- New app integrations
|
||||
- New backend modules or RPC endpoints (unless fixing existing bugs or beta telemetry)
|
||||
- New dependencies (unless required for beta infrastructure)
|
||||
- Scope creep of any kind
|
||||
|
||||
### Status tracking
|
||||
- **Progress tracker**: `docs/BETA-PROGRESS.md` — updated every session
|
||||
- **Beta checklist**: `docs/BETA-RELEASE-CHECKLIST.md` — the acceptance criteria
|
||||
- **Master plan**: `docs/MASTER_PLAN.md` — phased roadmap (Phase 1/2/3)
|
||||
|
||||
### Session protocol
|
||||
1. Read `docs/BETA-PROGRESS.md` at start of every session
|
||||
2. Report current phase and status before starting work
|
||||
3. Work only on current-phase items
|
||||
4. Update `docs/BETA-PROGRESS.md` at end of every session with what changed
|
||||
Track: `docs/BETA-PROGRESS.md` | Checklist: `docs/BETA-RELEASE-CHECKLIST.md`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
# Frontend local dev (mock backend on :5959, Vite on :8100)
|
||||
cd neode-ui && npm start
|
||||
|
||||
# Deploy to live server (frontend + backend + restart services)
|
||||
./scripts/deploy-to-target.sh --live
|
||||
|
||||
# Deploy to both servers
|
||||
./scripts/deploy-to-target.sh --both
|
||||
|
||||
# Frontend build (outputs to web/dist/neode-ui/)
|
||||
cd neode-ui && npm run build
|
||||
|
||||
# Type-check frontend
|
||||
cd neode-ui && npm run type-check
|
||||
|
||||
# Rust checks (run on dev server, NOT macOS)
|
||||
cargo clippy --all-targets --all-features
|
||||
cargo fmt --all
|
||||
cargo test --all-features
|
||||
cd neode-ui && npm start # Local dev (mock backend :5959, Vite :8100)
|
||||
cd neode-ui && npm run build # Build (outputs to web/dist/neode-ui/)
|
||||
./scripts/deploy-to-target.sh --live # Deploy to live server (.228)
|
||||
```
|
||||
|
||||
Dev server: `http://192.168.1.228` | Local frontend: `http://localhost:8100` (password: `password123`)
|
||||
## Infrastructure
|
||||
|
||||
| What | Where |
|
||||
|------|-------|
|
||||
| Dev server | `192.168.1.228` (SSH key: `~/.ssh/archipelago-deploy`) |
|
||||
| Secondary | `192.168.1.198` |
|
||||
| Git remote | `git.tx1138.com` (remote name: `tx1138`) |
|
||||
| App registry | `80.71.235.15:3000/archipelago/` (HTTP, insecure) |
|
||||
| CI runner | act_runner on .228, workflow: `.gitea/workflows/build-iso.yml` |
|
||||
| ISO builds | FileBrowser at `http://192.168.1.228:8083` → Builds/ |
|
||||
| SSH creds | Gitignored `scripts/deploy-config.sh` |
|
||||
| Web password | `password123` |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Debian 12 (Bookworm)
|
||||
├── Podman (rootless containers)
|
||||
├── Nginx (port 80 → proxies /rpc/, /ws/, /health to backend)
|
||||
├── Rust Backend (core/) — binary on port 5678
|
||||
│ ├── core/archipelago/ — Main binary, RPC endpoints
|
||||
│ ├── core/container/ — PodmanClient, manifest parser, dependency resolver, health monitor
|
||||
│ ├── core/security/ — AppArmor profiles, secrets manager, Cosign image verifier
|
||||
│ ├── core/performance/ — Resource manager
|
||||
│ └── core/parmanode/ — Parmanode compatibility layer
|
||||
Debian 12
|
||||
├── Podman (rootless, user archipelago)
|
||||
├── Nginx (80/443 → backend, app proxies)
|
||||
├── Rust Backend (core/) on 127.0.0.1:5678
|
||||
│ ├── core/archipelago/ — Binary, RPC, auth, sessions
|
||||
│ └── core/container/ — PodmanClient, manifests, health
|
||||
└── Vue.js UI (neode-ui/)
|
||||
├── src/api/ — RPC client (rpc-client.ts), WebSocket, container client
|
||||
├── src/stores/ — Pinia stores
|
||||
├── src/views/ — Page components
|
||||
├── src/components/ — Reusable components
|
||||
├── src/router/ — Vue Router
|
||||
├── src/types/ — TypeScript type definitions
|
||||
└── src/style.css — Global styles + Tailwind utilities
|
||||
├── src/api/rpc-client.ts — All backend communication
|
||||
├── src/stores/ — Pinia state
|
||||
├── src/views/ — Pages
|
||||
└── src/style.css — ALL styling (global classes only)
|
||||
```
|
||||
|
||||
### Data Paths (Server)
|
||||
**Data paths**: `/var/lib/archipelago/{app-id}/` (data), `/opt/archipelago/web-ui/` (frontend), `/usr/local/bin/archipelago` (binary)
|
||||
|
||||
- App data: `/var/lib/archipelago/{app-id}/`
|
||||
- Secrets: `/var/lib/archipelago/secrets/{app-id}/` (encrypted)
|
||||
- Frontend: `/opt/archipelago/web-ui/`
|
||||
- Backend binary: `/usr/local/bin/archipelago`
|
||||
- Systemd service: `/etc/systemd/system/archipelago.service`
|
||||
- Nginx config: `/etc/nginx/sites-available/archipelago`
|
||||
## Critical Rules
|
||||
|
||||
## CRITICAL Workflow Rules
|
||||
1. **Never build Rust on macOS** — deploy script handles cross-compilation via rsync + remote build
|
||||
2. **Always deploy after changes** — `./scripts/deploy-to-target.sh --live`
|
||||
3. **Frontend builds to `web/dist/neode-ui/`** — not `neode-ui/dist/`
|
||||
4. **Container images**: `scripts/image-versions.sh` is the single source of truth. All scripts use `$*_IMAGE` variables, never hardcoded registry paths.
|
||||
5. **Type-check before committing** — `cd neode-ui && npx vue-tsc -b --noEmit`
|
||||
|
||||
### 1. NEVER Build Rust on macOS for Linux
|
||||
## Frontend
|
||||
|
||||
Always rsync source to the Linux dev server and build there. Building on macOS and copying the binary causes Exec format errors.
|
||||
- `<script setup lang="ts">` always — no Options API
|
||||
- Global CSS in `style.css` — **never inline Tailwind**
|
||||
- `.glass-button` for ALL buttons — `.gradient-button` is BANNED
|
||||
- `.glass-card` for containers, `.path-option-card` for interactive cards
|
||||
- `translateZ(0)` + `isolation: isolate` on glass elements (Chromium compositor fix)
|
||||
- Pinia for state, typed RPC client, handle loading/error/empty states
|
||||
|
||||
## Backend (Rust)
|
||||
|
||||
- No `unwrap()`/`expect()` — use `?` with `.context()`
|
||||
- `tracing` for logging, never `println!` or log secrets
|
||||
- Backend binds `127.0.0.1` only — nginx handles external access
|
||||
- Validate all input before path construction — reject `..`, `/`, null bytes
|
||||
- `tokio` runtime, timeouts on all external ops
|
||||
|
||||
## Security (Post-Pentest)
|
||||
|
||||
- RBAC: explicit method allowlists, never prefix matching
|
||||
- Session cookies: `SameSite=Lax; HttpOnly; Path=/`
|
||||
- Rate-limit auth endpoints, rotate tokens after privilege escalation
|
||||
- Validate redirect URLs with `isLocalRedirect()`, never `v-html` with user input
|
||||
- Container security: drop ALL caps, add only required, `no-new-privileges`, memory limits, health checks
|
||||
- See `.claude/rules/` for detailed crypto, API, container, and Bitcoin rules
|
||||
|
||||
## ISO Build & CI
|
||||
|
||||
CI builds on every push to `main` via git.tx1138.com Actions.
|
||||
|
||||
```bash
|
||||
# Deploy does this automatically:
|
||||
./scripts/deploy-to-target.sh --live
|
||||
# Manual build on .228:
|
||||
ssh archipelago@192.168.1.228
|
||||
cd ~/archy/image-recipe
|
||||
sudo UNBUNDLED=1 DEV_SERVER=localhost BUILD_FROM_SOURCE=0 ./build-auto-installer-iso.sh
|
||||
```
|
||||
|
||||
### 2. Always Deploy After Changes
|
||||
|
||||
After editing code (frontend, backend, scripts, or configs), deploy to the live server. Do not leave deployment to the user.
|
||||
|
||||
### 3. Frontend Build Output Path
|
||||
|
||||
Frontend builds to `web/dist/neode-ui/` — NOT `neode-ui/dist/`.
|
||||
|
||||
### 4. Deploy-Test-Fix Loop
|
||||
|
||||
1. Make the change
|
||||
2. Deploy with `./scripts/deploy-to-target.sh --live`
|
||||
3. Test at http://192.168.1.228
|
||||
4. If broken, fix and redeploy — repeat until working
|
||||
5. End loop only when everything works
|
||||
|
||||
### 5. SSH Access
|
||||
|
||||
- **Primary**: `archipelago@192.168.1.228` — password: `EwPDR8q45l0Upx@`
|
||||
- **Secondary**: `archipelago@192.168.1.198`
|
||||
- Credentials stored in gitignored `scripts/deploy-config.sh`
|
||||
|
||||
**Debugging fresh installs** — SSH in and check:
|
||||
```bash
|
||||
sshpass -p 'EwPDR8q45l0Upx@' ssh -o StrictHostKeyChecking=no archipelago@192.168.1.228
|
||||
cat /var/log/archipelago-install.log # Full installer output
|
||||
cat /var/log/archipelago-first-boot-diagnostics.log # Service status, nginx, LUKS, etc.
|
||||
sudo archipelago-diagnostics # Re-run diagnostics anytime
|
||||
```
|
||||
|
||||
## Frontend Rules (Vue.js + TypeScript)
|
||||
|
||||
### Component Standards
|
||||
|
||||
- **Always** `<script setup lang="ts">` — never Options API, never plain JS
|
||||
- **Pinia** for all state management — focused single-purpose stores
|
||||
- **TypeScript strict mode** — no `any`, use `unknown` or proper types
|
||||
- Export types from dedicated `.types.ts` files
|
||||
- Use type guards for runtime type checking
|
||||
|
||||
### Styling — Global Classes Only
|
||||
|
||||
- **ALWAYS** create global utility classes in `neode-ui/src/style.css`
|
||||
- **NEVER** use inline Tailwind classes directly in components
|
||||
- Use semantic class names: `.glass-card`, `.glass-button`, `.gradient-button`, `.path-option-card`
|
||||
|
||||
### API Client Rules
|
||||
|
||||
- Use `@/api/rpc-client.ts` for RPC calls, `@/api/container-client.ts` for containers
|
||||
- **NEVER** hardcode API endpoints — use environment variables
|
||||
- Handle loading states, error states, retry logic for all async operations
|
||||
|
||||
### CSS Class Hierarchy
|
||||
|
||||
| Class | Use | Hover |
|
||||
|-------|-----|-------|
|
||||
| `.path-option-card` | Section containers, interactive cards (Settings-style) | Lifts -2px |
|
||||
| `.glass-card` | Content containers, modals, panels | No |
|
||||
| `.info-card` | Status badges, metric displays | No |
|
||||
| `.info-card-button` | Action buttons inside info sections | Lifts, brightens |
|
||||
| `bg-black/20 rounded-xl border border-white/10` | Info sub-cards inside sections | No |
|
||||
| `bg-white/5` | Simple read-only info rows | No |
|
||||
| `.glass-button` | ALL buttons (primary and secondary) | Subtle brighten |
|
||||
| `.path-action-button` | Large action buttons (Logout, Continue) | Lifts -2px |
|
||||
|
||||
### BANNED Classes — Do NOT Use
|
||||
- **`.gradient-button`** — REMOVED. Use `.glass-button` instead. The gradient style breaks the clean glass aesthetic.
|
||||
- **`.gradient-card`** / **`.gradient-card-dark`** — REMOVED. Use `.glass-card` or `.path-option-card` instead.
|
||||
|
||||
### Design Tokens
|
||||
|
||||
- **Font**: Avenir Next (primary), Montserrat (`font-archipelago`)
|
||||
- **Spacing**: 4px grid system, 16px default padding
|
||||
- **Glassmorphism**: `background: rgba(0,0,0,0.60)`, `backdrop-filter: blur(24px)`, `inset 0 1px 0 rgba(255,255,255,0.22)`
|
||||
- **Transitions**: `all 0.3s ease` standard, `translateY(-2px)` hover, `translateY(1px)` active
|
||||
- **Accent orange** (Bitcoin): `#fb923c` — `#f59e0b`
|
||||
- **Green** (success): `#4ade80` | **Red** (danger): `#ef4444` | **Blue** (info): `#3b82f6`
|
||||
- **Text**: `rgba(255,255,255,0.9)` primary, `rgba(255,255,255,0.6-0.7)` muted
|
||||
|
||||
### Tailwind Custom Values
|
||||
|
||||
- Blur: `backdrop-blur-glass` (18px), `backdrop-blur-glass-strong` (24px)
|
||||
- Colors: `glass-dark` (0,0,0,0.35), `glass-darker` (0,0,0,0.6), `glass-border` (255,255,255,0.18)
|
||||
- Shadows: `shadow-glass`, `shadow-glass-inset`
|
||||
|
||||
## Backend Rules (Rust)
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **No `unwrap()` or `expect()` in production code** — use `?` operator
|
||||
- `thiserror` for library error types, `anyhow` for application errors
|
||||
- Custom error types per module: `{module}::Error`
|
||||
- Include context: `.context("What failed and why")`
|
||||
|
||||
### RPC Endpoints
|
||||
|
||||
- Use `rpc_toolkit::command` macro for all endpoints
|
||||
- Use `#[context] ctx: RpcContext` for context
|
||||
- Return `Result<T, Error>` — validate all inputs before processing
|
||||
|
||||
### Async & Runtime
|
||||
|
||||
- `tokio` runtime only — never mix with other async runtimes
|
||||
- Set timeouts on all external operations
|
||||
- Use `select!` for racing futures with timeouts
|
||||
- Handle shutdown gracefully with cancellation tokens
|
||||
|
||||
### Code Organization
|
||||
|
||||
- New modules in `core/{module-name}/`, add to `core/Cargo.toml` members
|
||||
- `snake_case` for all modules/files
|
||||
- Run `cargo clippy --all-targets --all-features` and `cargo fmt --all` before commits
|
||||
|
||||
### Logging
|
||||
|
||||
- Use `tracing` for structured logging — never `println!`
|
||||
- Never log secrets, passwords, keys, or tokens
|
||||
- Include context: `tracing::info!(user_id = %id, "Action")`
|
||||
|
||||
## Container & Security
|
||||
|
||||
### App Manifests
|
||||
|
||||
- All manifests in `apps/{app-id}/manifest.yml`
|
||||
- Follow spec in `docs/app-manifest-spec.md`
|
||||
- Use `archipelago_container::PodmanClient` — **NEVER** call Docker directly
|
||||
|
||||
### Security Requirements (Non-Negotiable)
|
||||
|
||||
- **ALWAYS** `readonly_root: true` unless explicitly needed
|
||||
- **ALWAYS** drop all capabilities, add only required ones
|
||||
- **ALWAYS** run as non-root user (UID > 1000)
|
||||
- **ALWAYS** `no-new-privileges: true`
|
||||
- **NEVER** use `latest` tag — pin specific image versions
|
||||
- **NEVER** hardcode secrets — use `core/security/secrets_manager.rs`
|
||||
|
||||
### App Icons
|
||||
|
||||
Single source of truth: `neode-ui/public/assets/img/app-icons/`
|
||||
Naming: `{app-id}.{png|webp|svg}` — do not duplicate elsewhere.
|
||||
|
||||
## Security Standards (Post-Pentest — Mandatory)
|
||||
|
||||
These rules come from a full penetration test (33 findings, all remediated). Follow them for ALL new code.
|
||||
|
||||
### Backend (Rust)
|
||||
|
||||
- **Backend binds to 127.0.0.1 ONLY** — never `0.0.0.0`. All external access goes through nginx.
|
||||
- **Validate ALL user input before path construction** — reject `..`, `/`, `\`, null bytes. Use the existing `validate_app_id()` pattern in `tor.rs`.
|
||||
- **Never pass user input to `sudo` commands** — if unavoidable, validate strictly against an allowlist of characters `[a-zA-Z0-9_-]`.
|
||||
- **Every HTTP endpoint that returns sensitive data MUST check authentication** — use `self.is_authenticated(&headers).await` or be in `UNAUTHENTICATED_METHODS` with justification.
|
||||
- **Rate-limit authentication endpoints** — `extract_client_ip()` must only trust `X-Real-IP` from the loopback interface (127.0.0.1).
|
||||
- **Federation messages require ed25519 signatures** — never accept unsigned peer-joined messages.
|
||||
- **RBAC: use explicit allowlists, not prefix matching** — `method.starts_with("node.")` is BANNED. List exact methods per role.
|
||||
- **Session cookies: `SameSite=Lax; HttpOnly; Path=/`** — `Strict` breaks iframe app fetches. `Lax` still prevents CSRF on POST.
|
||||
- **Destructive operations require password re-verification** — factory reset, onboarding reset, identity export.
|
||||
- **Remember-me secrets: use `OsRng` random bytes** — never derive from `/etc/machine-id` or other public data.
|
||||
- **Rotate session tokens after privilege escalation** — TOTP verification must issue a new token, invalidating the pending one.
|
||||
- **Tar archive extraction: validate every entry path** — never use `archive.unpack()`. Iterate entries and verify no `..` components or paths escaping the target directory.
|
||||
|
||||
### Frontend (Vue/TypeScript)
|
||||
|
||||
- **Validate redirect URLs** — use `isLocalRedirect()` from `router/index.ts` before any `window.location.href` assignment. Reject `javascript:`, protocol-relative (`//`), and external URLs.
|
||||
- **Never use `v-html` with user input** — if unavoidable, always sanitize with `DOMPurify.sanitize()`.
|
||||
- **CSP: no `unsafe-inline` in `script-src`** — Vite builds don't need it. Keep `unsafe-inline` only in `style-src` for Tailwind.
|
||||
|
||||
### Nginx
|
||||
|
||||
- **Session validation: `$cookie_session` (not `$cookie_session_id`)** — cookie name must match the Rust backend's `session=` cookie.
|
||||
- **Prefer `auth_request` over cookie-presence checks** — `if ($cookie_session = "")` only checks presence, not validity. For sensitive endpoints, use nginx `auth_request` to validate against the backend.
|
||||
- **All `/app/*` proxies are unauthenticated at nginx level** — each app must handle its own auth. Never expose apps with default credentials (change Grafana `admin/admin` on first boot, etc.).
|
||||
|
||||
### SSRF Prevention
|
||||
|
||||
- **Validate all user-supplied URLs** — require `https://` scheme, reject private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, ::1, fc00::/7).
|
||||
- **Disable redirect following** — use `redirect(Policy::none())` on reqwest clients that fetch user-supplied URLs.
|
||||
- **Onion addresses: validate v3 format** — exactly 56 base32 `[a-z2-7]` chars + `.onion`.
|
||||
- **Webhook URLs: parse with `Url::parse`** — don't split on `:` for host extraction (breaks IPv6).
|
||||
|
||||
### Container Security
|
||||
|
||||
- **Memory limits on every container** — use `--memory=$(mem_limit <name>)` pattern from `first-boot-containers.sh`. Prevents one container from OOM-killing the system.
|
||||
- **Health checks on every container** — define via `--health-cmd` in `podman run`.
|
||||
- **User-stopped tracking** — when a user stops a container via UI, record in `user-stopped.json` so crash recovery and health monitor don't auto-restart it.
|
||||
|
||||
## Code Quality
|
||||
|
||||
- Zero compiler warnings (Rust and TypeScript)
|
||||
- Zero linter errors (clippy, eslint)
|
||||
- Functions under 50 lines, single responsibility
|
||||
- Comment WHY not WHAT — code should be self-documenting
|
||||
- Remove dead code entirely — never comment it out
|
||||
- No `TODO`/`FIXME` in commits — fix now or create issues
|
||||
- Workspace-relative paths only — **NEVER** hardcode `/Users/dorian/...`
|
||||
|
||||
## Git Conventions
|
||||
|
||||
### Commit Format
|
||||
|
||||
```
|
||||
type: description
|
||||
```
|
||||
|
||||
**Types**: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`, `perf:`
|
||||
|
||||
### Rules
|
||||
|
||||
- Atomic commits — one logical change per commit
|
||||
- `main` branch always production-ready
|
||||
- Feature branches: `feature/description`, bug fixes: `fix/description`
|
||||
- Never commit secrets, `.env` files, or credentials
|
||||
- Tag releases: `v1.2.3` (SemVer)
|
||||
**Kiosk**: X11 on VT7, console on VT1. `Ctrl+Alt+F1` for terminal, `Ctrl+Alt+F7` for kiosk.
|
||||
Toggle: `sudo archipelago-kiosk enable|disable|toggle`
|
||||
|
||||
## App Integration Checklist
|
||||
|
||||
When adding or fixing apps, **every file below must be checked**. Missing any one causes failures on fresh installs.
|
||||
When adding/fixing apps, check ALL of these:
|
||||
- `core/archipelago/src/api/rpc/package/` — config, capabilities, deps
|
||||
- `neode-ui/src/views/marketplace/marketplaceData.ts` — marketplace entry
|
||||
- `image-recipe/configs/nginx-archipelago.conf` — proxy rules (HTTP + HTTPS)
|
||||
- `scripts/image-versions.sh` — pinned image version
|
||||
- `scripts/first-boot-containers.sh` — first boot creation
|
||||
- `scripts/deploy-to-target.sh` — deploy logic
|
||||
|
||||
### Backend (Rust)
|
||||
## Git
|
||||
|
||||
- [ ] `core/archipelago/src/api/rpc/package.rs` — `get_app_config()`: ports, volumes, env vars, custom args
|
||||
- [ ] `core/archipelago/src/api/rpc/package.rs` — `needs_archy_net`: add if app needs container DNS
|
||||
- [ ] `core/archipelago/src/api/rpc/package.rs` — `get_app_capabilities()`: add required caps (CHOWN, etc.)
|
||||
- [ ] `core/archipelago/src/api/rpc/package.rs` — dependency checks (e.g., electrs requires bitcoin)
|
||||
- [ ] `core/archipelago/src/container/docker_packages.rs` — `get_app_metadata()`: title, description, icon, repo
|
||||
- [ ] `core/archipelago/src/container/docker_packages.rs` — UI address mapping (e.g., `http://localhost:50002`)
|
||||
|
||||
### Frontend (Vue)
|
||||
|
||||
- [ ] `neode-ui/src/views/Marketplace.vue` — `getCuratedAppList()`: marketplace entry with dockerImage
|
||||
- [ ] `neode-ui/src/stores/appLauncher.ts` — port-to-proxy mapping (if app has custom UI port)
|
||||
- [ ] `neode-ui/src/views/AppDetails.vue` — route ID mapping (if app ID differs from container name)
|
||||
|
||||
### Nginx
|
||||
|
||||
- [ ] `image-recipe/configs/nginx-archipelago.conf` — `/app/{id}/` proxy in HTTP block
|
||||
- [ ] `image-recipe/configs/snippets/archipelago-https-app-proxies.conf` — `/app/{id}/` proxy in HTTPS block
|
||||
- [ ] Any custom status endpoints (e.g., `/electrs-status`) proxied before the SPA catch-all
|
||||
|
||||
### Deploy & First Boot
|
||||
|
||||
- [ ] `scripts/deploy-to-target.sh` — container creation/update logic
|
||||
- [ ] `scripts/first-boot-containers.sh` — container created on fresh ISO install
|
||||
- [ ] Custom UI containers (e.g., electrs-ui): built and started in both deploy and first-boot
|
||||
|
||||
### ISO Build
|
||||
|
||||
- [ ] `image-recipe/build-auto-installer-iso.sh` — `CAPTURE_PATTERNS`: image captured from live server
|
||||
- [ ] `image-recipe/build-auto-installer-iso.sh` — `CONTAINER_IMAGES`: fallback image pulled from registry
|
||||
- [ ] `image-recipe/build-auto-installer-iso.sh` — docker UI source files bundled for build fallback
|
||||
- [ ] `image-recipe/build-auto-installer-iso.sh` — installer copies files to target disk
|
||||
|
||||
### Runtime Verification
|
||||
|
||||
- [ ] Test the app UI loads on its configured port
|
||||
- [ ] Auto-connect dependencies (Bitcoin RPC, LND, etc.) — apps must work out of the box
|
||||
- [ ] Most apps launch in iframe; BTCPay (23000) and Home Assistant (8123) open in new tab (X-Frame-Options)
|
||||
|
||||
## ISO Build
|
||||
|
||||
Build on the target server (has all dependencies):
|
||||
|
||||
```bash
|
||||
ssh archipelago@192.168.1.228
|
||||
cd ~/archy/image-recipe
|
||||
sudo ./build-auto-installer-iso.sh
|
||||
# Result: results/archipelago-auto-installer-*.iso
|
||||
```
|
||||
|
||||
After testing on live server, always update ISO build to include changes. Sync system configs:
|
||||
- `archipelago.service` → `image-recipe/configs/`
|
||||
- `nginx-archipelago.conf` → `image-recipe/configs/`
|
||||
|
||||
## Key Documentation
|
||||
|
||||
- `docs/architecture.md` — System architecture
|
||||
- `docs/current-state.md` — Current development phase
|
||||
- `docs/development-setup.md` — Local dev setup
|
||||
- `docs/app-manifest-spec.md` — YAML manifest spec
|
||||
- `BUILD-GUIDE.md` — ISO build guide
|
||||
- `DEPLOYMENT.md` — Deployment details
|
||||
- `CHANGELOG.md` — Version history
|
||||
Commits: `type: description` (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`, `perf:`)
|
||||
Push to: `git push tx1138 main`
|
||||
|
||||
Reference in New Issue
Block a user