@@ -116,11 +116,14 @@ Pear may print `DEPRECATED: pear run is deprecated` (platform-wide). For day-to-
|
||||
|
||||
## What you get
|
||||
|
||||
- **Full Engine surface** over P2P: containers, images, volumes, networks, compose stacks, logs, stats, terminals, prune, schedules, registry vault
|
||||
- **Full Engine surface** over P2P: containers, images, volumes, networks, compose stacks, logs, stats, terminals, prune, schedules
|
||||
- **Registry vault + browser**: encrypted credentials, Hub search, remote catalog/tags/manifests, pull/push with vault auth
|
||||
- **Image update indicators** on containers (digest vs remote tag) with **Check updates** in the job tray
|
||||
- **Deploy templates** (Portainer-compatible container + stack templates) and blank **Add container** create form
|
||||
- **Docker Swarm** UI and RPC (services, nodes, tasks, secrets, configs, scale). On by default; set `ENABLE_SWARM=0` to disable
|
||||
- **Holesail tunnels** for published ports without firewall holes. On by default; set `ENABLE_HOLESAIL=0` to disable. See [docs/HOLESAIL.md](docs/HOLESAIL.md)
|
||||
- **Roles**: `viewer` / `operator` / `admin` (default **viewer**; admin via seed proof or pd1. invite)
|
||||
- **Multi-peer fleet** in one desktop client with reconnect and job tray
|
||||
- **Multi-peer fleet** in one desktop client with reconnect and a multi-step **job tray** (hybrid image pull progress)
|
||||
- **Standalone binaries** for six 64-bit hosts (server Bare + client Electron)
|
||||
|
||||
---
|
||||
@@ -140,9 +143,10 @@ client/
|
||||
connection.js Single HyperDHT + protomux-rpc link
|
||||
manager.js Multi-server connections + persistence
|
||||
api.js Typed RPC helpers
|
||||
jobs.js Job tray model + hybrid pull progress helpers
|
||||
holesailLocal.js Local Holesail client (data plane)
|
||||
electron/ Electron main / packaged desktop shell
|
||||
ui/ + app.js + libs/ Desktop UI
|
||||
ui/ + app.js + libs/ Desktop UI (deploy, registry, add-container, …)
|
||||
assets/ Logos + favicons
|
||||
peardock-branding/ Master brand package
|
||||
deploy/ systemd unit
|
||||
|
||||
@@ -74,7 +74,8 @@ flowchart TB
|
||||
API[client/api.js]
|
||||
MGR[client/manager.js]
|
||||
CON[client/connection.js]
|
||||
JOB[client/jobs.js]
|
||||
JOB[client/jobs.js + jobActions + pullProgress]
|
||||
TPL[client/templateResolve.js]
|
||||
CACHE[client/peerCache.js]
|
||||
end
|
||||
|
||||
@@ -219,7 +220,7 @@ flowchart TB
|
||||
|
||||
- Disk-backed peer list + last active id.
|
||||
- Switching peers rebinds UI subscriptions to the active connection’s pushes.
|
||||
- Jobs (`client/jobs.js`) track long ops (pull, deploy, build) with step logs.
|
||||
- Jobs (`client/jobs.js` + `client/jobActions.js`) track long ops (pull, deploy, build, bulk lifecycle, prune) with step logs and hybrid image-pull progress (`client/pullProgress.js`).
|
||||
|
||||
---
|
||||
|
||||
@@ -323,7 +324,7 @@ Files (server data dir / cwd):
|
||||
|
||||
## Protocol versioning
|
||||
|
||||
- Constant: `PROTOCOL_VERSION` in `shared/protocol.js` (currently **2**).
|
||||
- Constant: `PROTOCOL_VERSION` in `shared/protocol.js` (currently **3** — HMAC auth handshake with capability + adminProof).
|
||||
- Negotiated in `handshake`.
|
||||
- **Bump** when breaking RPC argument/result shapes.
|
||||
- Additive methods may land without a bump if clients ignore unknowns.
|
||||
|
||||
+47
-10
@@ -45,10 +45,15 @@ flowchart TB
|
||||
- **Reconnect**: every **5s** after unexpected drop (unlimited by default).
|
||||
- Persists peers via `peerCache.js`.
|
||||
- Restores last active peer on launch.
|
||||
- Longer timeouts for slow methods (`checkImageUpdates`, `deployStack`, pulls).
|
||||
|
||||
### `client/api.js`
|
||||
|
||||
Thin typed wrappers around `Methods.*` for UI code (e.g. `listContainers`, `createTunnel`, `swarmInspect`).
|
||||
Thin typed wrappers around `Methods.*` for UI code (e.g. `listContainers`, `checkImageUpdates`, `createTunnel`, `swarmInspect`).
|
||||
|
||||
### `client/identity.js`
|
||||
|
||||
Stable client DHT keypair helpers for reconnect identity.
|
||||
|
||||
---
|
||||
|
||||
@@ -61,11 +66,34 @@ Thin typed wrappers around `Methods.*` for UI code (e.g. `listContainers`, `crea
|
||||
|
||||
Location: config directory suitable for the runtime (XDG / Pear storage / Electron userData depending on path helpers).
|
||||
|
||||
Client saved hosts are edited under **Settings → Peers** (not a top-level sidebar item). Server ACL / invites live under **Access**.
|
||||
|
||||
---
|
||||
|
||||
## Jobs
|
||||
## Jobs and job tray
|
||||
|
||||
`client/jobs.js` models multi-step operations (pull, deploy, build) for the **job drawer** in the UI: progress, logs, success/failure.
|
||||
Long-running Docker ops use a multi-step **job tray** (activity panel) instead of only status toasts.
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `client/jobs.js` | Job model: create/run, steps, logs, progress, rAF-coalesced paints, card rendering |
|
||||
| `client/jobActions.js` | Preferable entry for bulk lifecycle, recreate, image remove/push/build, prune, stack remove, single-container actions |
|
||||
| `client/pullProgress.js` | Aggregates Docker layer pull/push events into hybrid phase/%/bytes + fixed-height layer track |
|
||||
|
||||
Typical jobs: pull/push image, deploy container, add container, deploy stack (validate → pull images → compose up), check image updates, bulk start/stop/remove, prune.
|
||||
|
||||
Stack deploy job steps: `ui/ops-app.js` → `deployStackWithSteps`.
|
||||
|
||||
---
|
||||
|
||||
## Templates
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `client/templateLists.js` | Catalog list URLs / sources |
|
||||
| `client/templateResolve.js` | Portainer type 1 (container) vs 2/3 (stack): fetch stackfile, parse compose, pick app service, merge into form shape |
|
||||
| `libs/templateDeploy.js` | Deploy form, full Portainer field mapping, Duplicate/Edit modal |
|
||||
| `libs/addContainer.js` | Blank create form from Containers toolbar |
|
||||
|
||||
---
|
||||
|
||||
@@ -77,34 +105,39 @@ Sidebar `data-view="…"` sections, including:
|
||||
|
||||
| View | Purpose |
|
||||
|------|---------|
|
||||
| containers | Table + details, lifecycle actions; **Add container** header button |
|
||||
| containers | Table + details, lifecycle actions; **Add container** + **Check updates** in toolbar/action bar |
|
||||
| add-container | Blank create form (always-pull, ports, advanced); not in sidebar |
|
||||
| images | Local engine images (pull/push/build/prune) |
|
||||
| registry | Vault, Hub search, remote catalog/tags/manifests/delete |
|
||||
| networks / volumes | Resource management |
|
||||
| stacks | Compose projects |
|
||||
| stacks | Compose projects + stack deploy form (job tray) |
|
||||
| deploy | Templates + container configuration form |
|
||||
| swarm | Services, nodes, tasks, secrets, configs |
|
||||
| tunnels | Holesail create/list/close |
|
||||
| host | System info / df / maintenance |
|
||||
| access | Server peer ACL, invites, vault quick-store |
|
||||
| settings | Prefs + **Peers** subtab (client saved hosts) |
|
||||
| access | Server peer ACL, invites, revoke list |
|
||||
| settings | Prefs, **Peers** subtab (client saved hosts), **hidden-container label filters** |
|
||||
|
||||
### Controllers
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `ui/ops-app.js` | View loading, Swarm tables, tunnels, settings, connect hooks |
|
||||
| `ui/ops-app.js` | View loading, Swarm tables, tunnels, settings (hidden labels), connect hooks, stack deploy steps |
|
||||
| `ui/track-g-ux.js` | Keyboard shortcuts (`g` then key), command palette, go-map |
|
||||
| `ui/track-f-extras.js` | Extra polish features |
|
||||
| `libs/templateDeploy.js` | Deploy form / templates (large) |
|
||||
| `libs/addContainer.js` | Add container blank create form |
|
||||
| `libs/registryManager.js` | Registry view: vault, browser, pull/push helpers |
|
||||
| `libs/terminal.js` etc. | xterm integration |
|
||||
| `app.js` | Large shell glue: tables, container details, image-update column, list filtering |
|
||||
|
||||
### Settings: hide containers by label
|
||||
|
||||
Stored in client settings (`hiddenContainerLabels`): array of `{ name, value? }`. Empty `value` matches any value for that label key. Applied when rendering the containers list (client-side only).
|
||||
|
||||
### Auto-refresh
|
||||
|
||||
When a view is active, silent polls refresh lists (e.g. Swarm fingerprint skip if unchanged).
|
||||
When a view is active, silent polls refresh lists (e.g. Swarm fingerprint skip if unchanged). Logs re-follow correctly after leaving and returning to the Logs tab.
|
||||
|
||||
---
|
||||
|
||||
@@ -153,7 +186,7 @@ OTA helpers: `electron/ota.cjs`. Preload isolates privileged APIs.
|
||||
|
||||
- Map RPC codes to human messages.
|
||||
- Background methods may soft-fail without modal spam.
|
||||
- Job tray owns multi-step failure UX.
|
||||
- Job tray owns multi-step failure UX (title, message, recovery).
|
||||
|
||||
---
|
||||
|
||||
@@ -174,6 +207,10 @@ Server env flags do not automatically apply to the client; the server enforces f
|
||||
- `test/peer-cache.test.js`
|
||||
- `test/holesail-local.test.js`
|
||||
- `test/visual-structure.test.js` (critical `index.html` ids)
|
||||
- `test/template-resolve.test.js`
|
||||
- `test/pull-progress.test.js`
|
||||
- `test/image-updates.test.js`
|
||||
- `test/registry-client.test.js`
|
||||
- `test/terminal-shells.test.js`
|
||||
- `test/feedback.test.js` / `errors.test.js`
|
||||
|
||||
|
||||
+34
-18
@@ -70,9 +70,10 @@ flowchart LR
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `protocol.js` | `PROTOCOL`, `PROTOCOL_VERSION`, `Roles`, `MethodRoles`, `Methods`, `Pushes`, `roleAllows()` |
|
||||
| `protocol.js` | `PROTOCOL`, `PROTOCOL_VERSION` (**3**), `Roles`, `MethodRoles`, `Methods`, `Pushes`, `roleAllows()` |
|
||||
| `encodings.js` | compact-encoding setup for protomux-rpc value codec |
|
||||
| `schema.js` | `validateMethodArgs()` lightweight arg validation + `SCHEMA_VERSION` |
|
||||
| `crypto-auth.js` | HKDF + HMAC for admin seed proof and pd1. capability grants |
|
||||
|
||||
**Rule:** any new RPC method needs:
|
||||
|
||||
@@ -105,7 +106,9 @@ Process bootstrap:
|
||||
| `audit.js` | Privileged method audit log append |
|
||||
| `peer-policy.js` | Invites, allowlist, revoke, redeem invite |
|
||||
| `peer-registry.js` | Live connected sessions map |
|
||||
| `registry-vault.js` | AES-GCM credential crypto helpers |
|
||||
| `registry-vault.js` | AES-GCM credential crypto helpers (Bare-safe KDF; no Node-only scryptSync) |
|
||||
| `auth-keys.js` | Auth key material helpers for seed/capability verification |
|
||||
| `connection-invites.js` | Connection invite packaging helpers (pd1. flow) |
|
||||
|
||||
### `server/rpc/`
|
||||
|
||||
@@ -119,20 +122,21 @@ Process bootstrap:
|
||||
|
||||
| File | Domain |
|
||||
|------|--------|
|
||||
| `containers.js` | list/start/stop/inspect/exec/… |
|
||||
| `images.js` | pull/push/build/prune/search/load/save |
|
||||
| `containers.js` | list/start/stop/inspect/exec/…; graceful stop-then-remove; `checkImageUpdates` |
|
||||
| `images.js` | pull/push/build/prune/search/load/save (vault `credentialId`) |
|
||||
| `networks.js` | network CRUD + connect/disconnect |
|
||||
| `volumes.js` | volume CRUD + browse |
|
||||
| `stacks.js` | compose stacks, ps, logs, git sync |
|
||||
| `deploy.js` | high-level `deployContainer` / deploy flows |
|
||||
| `stacks.js` | compose stacks, ps, logs, git sync; remove removes project networks |
|
||||
| `deploy.js` | high-level `deployContainer` / always-pull / deploy flows |
|
||||
| `terminal.js` | interactive shells (multi-shell probe) |
|
||||
| `logs.js` | log streams |
|
||||
| `logs.js` | log streams (re-follow safe across tab switches) |
|
||||
| `docker-cli.js` | allow-listed docker CLI passthrough |
|
||||
| `system.js` | info, df, prune, metrics, schedules, browse host |
|
||||
| `swarm.js` | Swarm mode APIs (`ENABLE_SWARM`) |
|
||||
| `plugins.js` | Engine plugins (`ENABLE_PLUGINS`) |
|
||||
| `peers.js` | list/invite/revoke/role |
|
||||
| `vault.js` | registry credential vault RPC |
|
||||
| `vault.js` | registry credential vault RPC (store/use/test/session) |
|
||||
| `registry.js` | Remote Registry HTTP API V2 browser (catalog/tags/manifest/delete) |
|
||||
| `tunnels.js` | Holesail tunnel RPC |
|
||||
| `suggestions.js` | smart defaults for deploy UI |
|
||||
|
||||
@@ -140,13 +144,15 @@ Process bootstrap:
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `docker.js` | Shared dockerode instance / socket |
|
||||
| `docker.js` | Shared dockerode instance / socket; timed raw stop/kill/delete helpers |
|
||||
| `events.js` | Docker event stream → pushes |
|
||||
| `stats.js` | Periodic stats broadcast |
|
||||
| `stats-history.js` | In-memory stats history for charts |
|
||||
| `metrics.js` | Process + RPC metrics |
|
||||
| `holesail-tunnels.js` | Create/list/close/restore Holesail servers |
|
||||
| `schedules.js` | Persisted scheduled maintenance jobs |
|
||||
| `image-updates.js` | Compare local `RepoDigest` to remote registry manifests |
|
||||
| `registry-client.js` | Registry HTTP V2 client (auth, catalog, tags, manifests, delete) |
|
||||
|
||||
### `server/utils/`
|
||||
|
||||
@@ -154,9 +160,9 @@ Process bootstrap:
|
||||
|------|------|
|
||||
| `logger.js` | Structured pretty/json logger + banner |
|
||||
| `rateLimiter.js` | Per-peer method rate limits; stream hot methods |
|
||||
| `validation.js` | Shared validation helpers |
|
||||
| `validation.js` | Shared validation helpers (deploy/duplicate configs) |
|
||||
| `dockerErrors.js` | Sanitize Docker errors for clients |
|
||||
| `composeManager.js` | Compose file deploy orchestration |
|
||||
| `composeManager.js` | Compose deploy/up; **remove** tears down project networks (`compose down` parity) |
|
||||
| `containerConfig.js` | Normalize create/deploy options |
|
||||
| `engine-capabilities.js` | Probe what Engine supports |
|
||||
| `gitops.js` | Git pull for stack sync |
|
||||
@@ -172,12 +178,16 @@ Process bootstrap:
|
||||
| `manager.js` | Multi-peer manager, active peer, reconnect loop |
|
||||
| `api.js` | Typed `request` wrappers for Methods |
|
||||
| `peerCache.js` | Persist peers + last active to disk |
|
||||
| `jobs.js` | Long-running job tray model |
|
||||
| `identity.js` | Client DHT identity helpers |
|
||||
| `jobs.js` | Job tray model: steps, logs, hybrid progress, rAF-coalesced UI |
|
||||
| `jobActions.js` | Multi-step tray actions (bulk lifecycle, pull/push, prune, stacks, …) |
|
||||
| `pullProgress.js` | Aggregate Docker layer pull/push events → hybrid tray snapshot |
|
||||
| `templateResolve.js` | Portainer type 1/2/3 template → form/stack resolve (compose fetch) |
|
||||
| `templateLists.js` | Template catalog lists |
|
||||
| `errors.js` | Normalize RPC errors for UI |
|
||||
| `holesailLocal.js` | Local hs:// client (HTTP to Bare control or in-process) |
|
||||
| `holesailBareControl.cjs` | Bare-side real `holesail` control HTTP API |
|
||||
| `snapshot.js` | UI snapshot helpers |
|
||||
| `templateLists.js` | Template catalog lists |
|
||||
| `index.js` | Small re-export surface |
|
||||
|
||||
```mermaid
|
||||
@@ -190,6 +200,10 @@ flowchart TB
|
||||
CON --> RPC[protomux-rpc]
|
||||
MGR --> CACHE[peerCache.js]
|
||||
UI --> JOBS[jobs.js]
|
||||
UI --> JA[jobActions.js]
|
||||
JA --> JOBS
|
||||
JA --> PP[pullProgress.js]
|
||||
UI --> TR[templateResolve.js]
|
||||
UI --> HS[holesailLocal.js]
|
||||
```
|
||||
|
||||
@@ -201,18 +215,20 @@ flowchart TB
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `ops-app.js` | Main ops controller: views, Swarm, tunnels, host, settings hooks |
|
||||
| `ops-app.js` | Main ops controller: views, Swarm, tunnels, host, settings (incl. hidden-label filters), stack deploy job steps |
|
||||
| `track-g-ux.js` | Keyboard shortcuts, go-to view map, command palette pieces |
|
||||
| `track-f-extras.js` | Additional UI extras from roadmap track F |
|
||||
| `track-f-extras.js` | Additional UI extras |
|
||||
| `components.js` | Shared UI components |
|
||||
| `modern.css` / `ops.css` / `styles.css` | Styling layers |
|
||||
| `modern.css` / `ops.css` / `styles.css` | Styling layers (tables, job tray, deploy cards) |
|
||||
|
||||
### `libs/`
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `templateDeploy.js` | Large deploy/template wizard logic |
|
||||
| `templateDeploy.js` | Deploy/template wizard; Portainer field mapping; Duplicate/Edit modal |
|
||||
| `templateStorage.js` | Template persistence |
|
||||
| `addContainer.js` | Blank **Add container** create form (always-pull, ports, advanced) |
|
||||
| `registryManager.js` | Registry view: vault, Hub search, remote catalog/tags/manifests |
|
||||
| `terminal.js` / `dockerTerminal.js` / `xtermUtils.js` / `termInput.js` | Terminal UX |
|
||||
| `notifications.js` | Toasts / activity |
|
||||
| `uiUtils.js` | DOM helpers, job stepper integration |
|
||||
@@ -220,7 +236,7 @@ flowchart TB
|
||||
|
||||
### `index.html`
|
||||
|
||||
Single-page app shell: sidebar views (containers, images, networks, volumes, stacks, deploy, Swarm, tunnels, host, peers, settings, …), modals, job drawer, toast stack.
|
||||
Single-page app shell: sidebar views (containers, images, **registry**, networks, volumes, stacks, deploy, Swarm, tunnels, host, **access**, settings, …), add-container page, modals, **job tray** / activity panel, toast stack. Client saved hosts live under **Settings → Peers** (not a top-level sidebar item).
|
||||
|
||||
---
|
||||
|
||||
|
||||
+41
-5
@@ -12,7 +12,8 @@ What PearDock can do today, mapped to code and protocol surfaces.
|
||||
| Image pull/build/load/save | shipped | on | `handlers/images.js` |
|
||||
| Networks / volumes | shipped | on | `handlers/networks.js`, `volumes.js` |
|
||||
| Compose stacks + GitOps | shipped | on | `handlers/stacks.js`, `utils/gitops.js` |
|
||||
| Deploy templates UI | shipped | on | `libs/templateDeploy.js` |
|
||||
| Deploy templates UI | shipped | on | `libs/templateDeploy.js`, `client/templateResolve.js` |
|
||||
| Image update indicators | shipped | on | `services/image-updates.js`, containers UI |
|
||||
| Logs follow | shipped | on | `handlers/logs.js` |
|
||||
| Interactive terminals | shipped | on | `handlers/terminal.js` |
|
||||
| Multi-shell probe | shipped | on | terminal handler + tests |
|
||||
@@ -21,6 +22,7 @@ What PearDock can do today, mapped to code and protocol surfaces.
|
||||
| System prune / df / info | shipped | on | `handlers/system.js` |
|
||||
| Schedules | shipped | on | `services/schedules.js` |
|
||||
| Registry vault | shipped | on | `handlers/vault.js`, `core/registry-vault.js` |
|
||||
| Registry browser (V2 API) | shipped | on | `handlers/registry.js`, `services/registry-client.js` |
|
||||
| Peer invites / revoke / roles | shipped | on | `handlers/peers.js`, `core/peer-policy.js` |
|
||||
| Audit log | shipped | opt-in env | `core/audit.js` |
|
||||
| Holesail tunnels | shipped | **on** | `handlers/tunnels.js`, `services/holesail-tunnels.js` |
|
||||
@@ -30,7 +32,8 @@ What PearDock can do today, mapped to code and protocol surfaces.
|
||||
| Binary streams | shipped | on | `rpc/binary-stream.js` |
|
||||
| Multi-peer fleet UI | shipped | on | `client/manager.js` |
|
||||
| Auto-reconnect 5s | shipped | on | `client/manager.js` |
|
||||
| Job tray | shipped | on | `client/jobs.js` |
|
||||
| Job tray + hybrid pull progress | shipped | on | `client/jobs.js`, `jobActions.js`, `pullProgress.js` |
|
||||
| Hidden containers by label | shipped | on | Settings → label filters (`ui/ops-app.js`) |
|
||||
| Keyboard UX | shipped | on | `ui/track-g-ux.js` |
|
||||
| Rolling binaries | shipped | CI | `scripts/gitea-rolling-release.sh` |
|
||||
| One-line installer | shipped | public | `scripts/install.sh` |
|
||||
@@ -42,11 +45,15 @@ What PearDock can do today, mapped to code and protocol surfaces.
|
||||
**UI:** Containers view + detail pane + **Add container** page (header button).
|
||||
**RPC:** list/inspect/start/stop/restart/kill/pause/unpause/remove/recreate/rename/update/deploy/bulk/top/stats/logs/exec/attach/commit/export/archive/duplicate/prune.
|
||||
|
||||
**Image update indicators** (style): **Updates** column compares each container’s local image `RepoDigest` to the remote registry manifest digest for the same tag. Green check = up to date, orange up-arrow = update available (click to pull), grey dash = unknown/skipped. **Check updates** forces a recheck. Server caches digests (~5m). Uses vault credentials for private registries. RPC: `checkImageUpdates`.
|
||||
**Image update indicators** (style): **Updates** column compares each container’s local image `RepoDigest` to the remote registry manifest digest for the same tag. Green check = up to date, orange up-arrow = update available (click to pull), grey dash = unknown/skipped. **Check updates** lives in the containers action bar and reports results in the **job tray**. Server caches digests (~5m). Uses vault credentials for private registries. RPC: `checkImageUpdates`.
|
||||
|
||||
**Add container** (`#add-container-view`, `libs/addContainer.js`) is a blank create form separate from **Deploy** templates: name, image, **Always pull the image**, ports (manual + publish-all-exposed), auto-remove, and advanced sections (command, volumes, network, env, labels, restart, runtime/resources). Submit uses `deployContainer` via the job tray.
|
||||
|
||||
**Duplicate / Edit** (`#duplicateModal`, `libs/templateDeploy.js`) reuses the same deploy path with a full config editor (name, image, **Always pull the image**, ports, volumes, env, resources, security, health, etc.). When always-pull is off, the server uses a local image if present.
|
||||
**Duplicate / Edit** (`#duplicateModal`, `libs/templateDeploy.js`) reuses the same deploy path with a full config editor (name, image, **Always pull the image**, ports, volumes, env, resources, security, health, etc.). Cloning preserves volumes/settings correctly. When always-pull is off, the server uses a local image if present.
|
||||
|
||||
**Remove** stops the container gracefully (short grace period, then kill fallback) before delete, with timed raw Docker operations so force-remove cannot hang the RPC.
|
||||
|
||||
**Hidden by label** (Settings): global filters `{ name, value? }` hide matching containers from the containers list (empty value matches any value for that label key). Client-side only; does not affect the Engine.
|
||||
|
||||
Deploy templates form remains under the Deploy tab for catalog-driven deploys.
|
||||
|
||||
@@ -93,9 +100,24 @@ Full CRUD for operators/admins per role table. Volume browse for inspecting file
|
||||
|
||||
## Stacks / Compose
|
||||
|
||||
- Deploy compose content (+ override, env file, profiles, build).
|
||||
- Deploy compose content (+ override, env file, profiles, build) via **Stacks** UI and job-tray steps: validate → pull images (hybrid progress) → `compose up` (`ui/ops-app.js` `deployStackWithSteps`).
|
||||
- List stacks, `ps`, logs, pull.
|
||||
- `syncStackFromGit` for GitOps-style refresh (`utils/gitops.js`).
|
||||
- **Remove stack** tears down project containers **and project-scoped networks** (compose `down` parity — volumes are kept). Built-in Docker networks are never removed.
|
||||
|
||||
---
|
||||
|
||||
## Deploy templates (Portainer-compatible)
|
||||
|
||||
**UI:** Deploy view + template catalog (`libs/templateDeploy.js`, `client/templateLists.js`, `client/templateResolve.js`).
|
||||
|
||||
| Template type | Behavior |
|
||||
|---------------|----------|
|
||||
| Type 1 — container | Maps Portainer fields (image, ports, volumes, env, restart, command, labels, …) into the deploy form |
|
||||
| Type 2 / 3 — stack | Resolves Git repository + stackfile, fetches compose, picks primary app service, merges into form or stack deploy path |
|
||||
| Long descriptions | Truncated in the catalog so the Deploy action stays on-screen |
|
||||
|
||||
Stack templates without a top-level `image` resolve compose from the repo so the form is not left empty.
|
||||
|
||||
---
|
||||
|
||||
@@ -144,6 +166,20 @@ See [HOLESAIL.md](./HOLESAIL.md).
|
||||
|
||||
---
|
||||
|
||||
## Job tray
|
||||
|
||||
Long-running ops report in a dedicated **job tray** (activity panel), not only toasts:
|
||||
|
||||
| Piece | Role |
|
||||
|-------|------|
|
||||
| `client/jobs.js` | Job model, steps, logs, progress patches, UI rendering |
|
||||
| `client/jobActions.js` | Bulk container ops, recreate, image remove/push/build, prune, stack remove, … |
|
||||
| `client/pullProgress.js` | Per-layer Docker pull/push aggregation → hybrid % + layer track |
|
||||
|
||||
Used by: image pull/push, container deploy/add, stack deploy, check-updates, bulk lifecycle, prune, and related ops.
|
||||
|
||||
---
|
||||
|
||||
## Observability
|
||||
|
||||
- Live stats push for container CPU/memory.
|
||||
|
||||
+13
-4
@@ -120,14 +120,17 @@ PEARDOCK_AUDIT=1
|
||||
|
||||
See [SECURITY_AUTH.md](./SECURITY_AUTH.md) for the full auth and invite model, and [THREAT_MODEL.md](./THREAT_MODEL.md) for hardening rationale.
|
||||
|
||||
## Registry vault
|
||||
## Registry vault and browser
|
||||
|
||||
Credentials encrypted at rest (AES-GCM derived from `SERVER_SEED`):
|
||||
Credentials encrypted at rest (AES-GCM; KDF is Bare-safe — no Node-only `scryptSync`):
|
||||
|
||||
- UI: **Access → Registry vault**
|
||||
- RPC: `vaultStoreCredential`, `vaultUseCredential`, `listVaultCredentials`
|
||||
- UI: top-level **Registry** view (vault credentials, Docker Hub search, remote catalog/tags/manifests)
|
||||
- RPC vault: `vaultStoreCredential`, `vaultUseCredential`, `vaultTestCredential`, `vaultClearSession` / `registryLogout`, `listVaultCredentials`
|
||||
- RPC browser: `registryCatalog`, `registryListTags`, `registryGetManifest`, `registryDeleteTag(s)`, `registryNormalizeEndpoint`
|
||||
- File: `peardock-vault.json` (mode 600). Override with `PEARDOCK_VAULT_PATH`.
|
||||
|
||||
Pull/push from **Images** and the registry browser can select a vault credential for private registries.
|
||||
|
||||
## Feature flags
|
||||
|
||||
| Env | Effect |
|
||||
@@ -171,6 +174,12 @@ sudo journalctl -u peardock -f
|
||||
- `profiles`: array or comma string
|
||||
- `build: true`: runs `docker compose up --build`
|
||||
|
||||
The desktop **Stacks** view deploys through the job tray (validate → optional image pulls → compose up). **Remove stack** deletes project containers and project-scoped networks (volumes are kept), matching `docker compose down` network behavior.
|
||||
|
||||
## Image update checks
|
||||
|
||||
Containers list can show whether a newer image digest is available for the running tag (`checkImageUpdates`). **Check updates** in the action bar runs a recheck and reports in the job tray. Private registries use vault credentials. Digests are cached on the server (~5 minutes).
|
||||
|
||||
## Swarm
|
||||
|
||||
When Docker is in Swarm mode, the client **Swarm** view lists services, nodes, tasks, secrets, and configs, and can scale replicated services. Server RPC covers init/join/leave, service CRUD, scale, logs, nodes, tasks, secrets, and configs. Disable the whole surface with `ENABLE_SWARM=0`.
|
||||
|
||||
+18
-5
@@ -127,10 +127,12 @@ Below is a **catalog** of `Methods` names. Minimum roles are in `MethodRoles` (s
|
||||
|
||||
| Method | Min role |
|
||||
|--------|----------|
|
||||
| `listContainers`, `inspectContainer`, `containerTop`, `containerStats`, `getStatsHistory`, `getContainerLogs` | viewer |
|
||||
| `listContainers`, `inspectContainer`, `checkImageUpdates`, `containerTop`, `containerStats`, `getStatsHistory`, `getContainerLogs` | viewer |
|
||||
| `startContainer`, `stopContainer`, `restartContainer`, `killContainer`, `pauseContainer`, `unpauseContainer`, `renameContainer`, `updateContainer`, `createContainer`, `deployContainer`, `bulkContainerOperation`, `waitContainer`, `attachContainer`, `attachInput`, `execContainer`, `execInput` | operator |
|
||||
| `removeContainer`, `recreateContainer`, `commitContainer`, `exportContainer`, `duplicateContainer`, `pruneContainers`, `archiveContainerGet`, `archiveContainerPut` | admin |
|
||||
|
||||
`checkImageUpdates` compares local image digests to remote registry manifests (vault credentials for private hosts). `removeContainer` stops gracefully (short grace + kill fallback) before delete so force-remove does not hang.
|
||||
|
||||
### Images
|
||||
|
||||
| Method | Min role |
|
||||
@@ -170,15 +172,26 @@ Below is a **catalog** of `Methods` names. Minimum roles are in `MethodRoles` (s
|
||||
| Method | Min role |
|
||||
|--------|----------|
|
||||
| `listVaultCredentials` | viewer |
|
||||
| `vaultUseCredential` | operator |
|
||||
| `vaultStoreCredential`, `vaultDeleteCredential` | admin |
|
||||
| `vaultUseCredential`, `vaultTestCredential`, `vaultClearSession` / `registryLogout` | operator |
|
||||
| `vaultStoreCredential`, `vaultDeleteCredential`, `registryLogin` | admin |
|
||||
|
||||
### Remote registry browser (Registry HTTP API V2)
|
||||
|
||||
| Method | Min role |
|
||||
|--------|----------|
|
||||
| `registryCatalog`, `registryListTags`, `registryGetManifest`, `registryNormalizeEndpoint` | viewer |
|
||||
| `registryDeleteTag`, `registryDeleteTags` | admin |
|
||||
|
||||
Uses vault credentials when the registry host matches a stored entry. Implemented in `handlers/registry.js` + `services/registry-client.js`.
|
||||
|
||||
### Peers / ACL
|
||||
|
||||
| Method | Min role |
|
||||
|--------|----------|
|
||||
| `listPeers`, `listInvites` | viewer |
|
||||
| `invitePeer`, `revokePeer`, `unrevokePeer`, `setPeerRole` | admin |
|
||||
| `listPeers` | viewer |
|
||||
| `listInvites`, `invitePeer`, `deleteInvite`, `revokePeer`, `unrevokePeer`, `listRevokedPeers`, `clearRevokedPeers`, `setPeerRole` | admin |
|
||||
|
||||
Invite strings are secrets — `listInvites` is **admin only**.
|
||||
|
||||
### Terminals / logs streams
|
||||
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
# PearDock documentation
|
||||
|
||||
**Complete technical documentation for the peardock codebase (v2.x / protocol version 2).**
|
||||
**Complete technical documentation for the peardock codebase (v2.x product / protocol version 3).**
|
||||
|
||||
PearDock is **decentralized Docker management**: a HyperDHT control plane, structured protomux-rpc, a desktop client (Electron or Pear), and optional Holesail L4 tunnels. There is no SaaS broker. You share a **public key**; peers hole-punch and talk end-to-end encrypted.
|
||||
|
||||
@@ -8,7 +8,7 @@ PearDock is **decentralized Docker management**: a HyperDHT control plane, struc
|
||||
|--|--|
|
||||
| **License** | [AGPL-3.0](../LICENSE) |
|
||||
| **Package** | `peardock` **2.0.1** (`package.json`) |
|
||||
| **Protocol** | `peardock/rpc` · `PROTOCOL_VERSION = 2` (`shared/protocol.js`) |
|
||||
| **Protocol** | `peardock/rpc` · `PROTOCOL_VERSION = 3` (`shared/protocol.js`) |
|
||||
| **Site** | [peardock.boats](https://peardock.boats) |
|
||||
| **Install** | `curl -fsSL https://install.peardock.boats \| bash` |
|
||||
| **Source** | [git.ssh.surf/snxraven/peardock](https://git.ssh.surf/snxraven/peardock) |
|
||||
@@ -26,7 +26,7 @@ PearDock is **decentralized Docker management**: a HyperDHT control plane, struc
|
||||
| **[PROTOCOL.md](./PROTOCOL.md)** | RPC methods, pushes, roles (`MethodRoles`), encodings, handshake |
|
||||
| **[SERVER.md](./SERVER.md)** | Server boot, PeerSession middleware, handlers, services, persistence |
|
||||
| **[CLIENT-UI.md](./CLIENT-UI.md)** | ConnectionManager, Electron vs Pear, UI views, jobs, local Holesail |
|
||||
| **[FEATURES.md](./FEATURES.md)** | Feature catalog by domain (containers, Swarm, tunnels, vault, …) |
|
||||
| **[FEATURES.md](./FEATURES.md)** | Feature catalog by domain (containers, registry, templates, Swarm, tunnels, vault, …) |
|
||||
|
||||
### Operating and shipping
|
||||
|
||||
@@ -140,16 +140,16 @@ sequenceDiagram
|
||||
|
||||
```
|
||||
peardock/
|
||||
├── shared/ # Protocol + encodings + arg schema (both sides)
|
||||
├── shared/ # Protocol + encodings + schema + crypto-auth (both sides)
|
||||
├── server/ # HyperDHT control plane + dockerode
|
||||
│ ├── server.js # Process entry
|
||||
│ ├── core/ # Keys, ACL, audit, peer policy, vault crypto
|
||||
│ ├── rpc/ # PeerSession, handler registration, binary streams
|
||||
│ ├── handlers/ # One module per domain
|
||||
│ ├── services/ # Docker client, events, stats, tunnels, schedules
|
||||
│ ├── handlers/ # One module per domain (incl. registry, vault, stacks)
|
||||
│ ├── services/ # Docker, events, stats, tunnels, image-updates, registry-client
|
||||
│ └── utils/ # Logger, rate limit, compose, validation
|
||||
├── client/ # Connection stack used by the UI
|
||||
├── ui/ + libs/ # Desktop presentation + helpers
|
||||
├── client/ # Connection stack, jobs, pull progress, template resolve
|
||||
├── ui/ + libs/ # Desktop presentation + helpers (deploy, registry, add-container)
|
||||
├── electron/ # Packaged Electron main / preload / OTA
|
||||
├── index.js # Pear entry (pear-electron + holesail Bare control)
|
||||
├── index.html # App shell markup
|
||||
@@ -200,7 +200,7 @@ flowchart LR
|
||||
| `ENABLE_HOLESAIL` | **on** | Tunnel RPC + Holesail servers |
|
||||
| `ENABLE_SWARM` | **on** | Swarm services/nodes/tasks/secrets/configs |
|
||||
| `ENABLE_PLUGINS` | **off** | Plugin install/enable/remove |
|
||||
| `PEARDOCK_DEFAULT_ROLE` | `admin` | Role for unknown peers |
|
||||
| `PEARDOCK_DEFAULT_ROLE` | `viewer` | Role for unknown peers |
|
||||
| `PEARDOCK_PEER_ALLOWLIST` | off | Require registered peers |
|
||||
| `PEARDOCK_AUDIT` | off | Append-only privileged audit log |
|
||||
|
||||
@@ -261,4 +261,4 @@ When you change behavior, update:
|
||||
4. Root `README.md` if install/flags/scripts changed
|
||||
5. Website legal/docs only if product claims change
|
||||
|
||||
Last aligned with codebase layout and protocol as of peardock **2.0.1** / `PROTOCOL_VERSION` **2**.
|
||||
Last aligned with codebase layout and protocol as of peardock **2.0.1** / `PROTOCOL_VERSION` **3**.
|
||||
|
||||
+21
-8
@@ -80,7 +80,7 @@ Handlers/services call into the session to `rpc.event` / push helpers so all con
|
||||
```
|
||||
handshake, system, containers, images, networks, volumes,
|
||||
stacks, deploy, terminal, logs, docker-cli, swarm, plugins,
|
||||
peers, vault, binary-stream, suggestions, tunnels
|
||||
peers, vault, registry, binary-stream, suggestions, tunnels
|
||||
```
|
||||
|
||||
On session close: kill terminals, stop log follows, end exec streams, clear `session.state`.
|
||||
@@ -89,7 +89,7 @@ On session close: kill terminals, stop log follows, end exec streams, clear `ses
|
||||
|
||||
## Docker access
|
||||
|
||||
`server/services/docker.js` exports a shared **dockerode** client (default socket).
|
||||
`server/services/docker.js` exports a shared **dockerode** client (default socket), plus timed raw stop/kill/delete helpers used for reliable force-remove.
|
||||
|
||||
Operational requirement: process user must access the socket (installer uses user `peardock` + group `docker`).
|
||||
|
||||
@@ -113,6 +113,14 @@ Process memory, RPC counters, latency percentiles, feature flags. Exposed via `g
|
||||
|
||||
Persisted jobs (prune, etc.) restored at boot; admin upsert/delete via RPC.
|
||||
|
||||
### Image updates (`services/image-updates.js`)
|
||||
|
||||
Compares local image `RepoDigest` values to remote registry manifest digests (with vault credentials for private hosts). Cached ~5 minutes. Wired as `checkImageUpdates` in `handlers/containers.js`. Works on Bare (no Node-only registry APIs).
|
||||
|
||||
### Registry client (`services/registry-client.js`)
|
||||
|
||||
Registry HTTP API V2: catalog, tags, manifests, delete; used by `handlers/registry.js`.
|
||||
|
||||
### Holesail tunnels (`services/holesail-tunnels.js`)
|
||||
|
||||
- Feature flag `ENABLE_HOLESAIL`
|
||||
@@ -151,23 +159,28 @@ flowchart LR
|
||||
|
||||
| Handler | Typical Engine surface |
|
||||
|---------|------------------------|
|
||||
| containers | ContainerLifecycle + exec/attach |
|
||||
| images | Image pull/build/load/save |
|
||||
| containers | Container lifecycle + exec/attach; graceful stop-then-remove; image update checks |
|
||||
| images | Image pull/push/build/load/save (optional vault `credentialId`) |
|
||||
| networks | Network API |
|
||||
| volumes | Volume API + browse |
|
||||
| stacks | Compose project ops + gitops |
|
||||
| deploy | Opinionated container deploy |
|
||||
| stacks | Compose project ops + gitops; remove drops project networks |
|
||||
| deploy | Opinionated container deploy (`alwaysPull`) |
|
||||
| terminal | Multiplexed interactive shells |
|
||||
| logs | Log follow |
|
||||
| logs | Log follow (safe re-subscribe) |
|
||||
| docker-cli | Allow-listed CLI |
|
||||
| system | info/df/prune/schedules/browse |
|
||||
| swarm | Swarmkit APIs |
|
||||
| plugins | Plugin APIs |
|
||||
| peers | ACL administration |
|
||||
| vault | Credential CRUD + use |
|
||||
| vault | Credential CRUD + test + session |
|
||||
| registry | Remote registry browser (V2 catalog/tags/manifest/delete) |
|
||||
| tunnels | Holesail |
|
||||
| suggestions | Deploy UX helpers |
|
||||
|
||||
### Compose manager (`utils/composeManager.js`)
|
||||
|
||||
Deploys compose projects and, on stack remove, removes project containers then **project-scoped networks** (compose `down` parity; volumes retained).
|
||||
|
||||
---
|
||||
|
||||
## Rate limiting
|
||||
|
||||
Reference in New Issue
Block a user