[grade=B urn:ump:zluxbji5tepzdqybrctqfyjdvbfin2o66atw6rwykg6vdwkzhfsa] backlog v3: P6 Shipdeck era (DC-109-119) cross-platform + barrier-removal lane
- DC-109-112: native runtime, installer remote mode, self-distribution, updater v2 (Shipdeck engine; v0 DoD-verified) - DC-113-115: first-run doctor, auth-gate helper, update nudge - DC-116-119: Podman runtime, service-control abstraction, Mac signing (electron-builder, 5 acceptance gates), 3-OS CI matrix - DC-P6-EVIDENCE.md: verbatim live-state evidence (E1-E6) backing the claims - DC-102 status corrected (mismatched DiskSpaceMonitor annotation)
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
# DashCaddy Production-Grade Backlog (v2)
|
||||
# DashCaddy Production-Grade Backlog (v3)
|
||||
|
||||
> Generated 2026-08-12 from a full codebase audit.
|
||||
> Generated 2026-08-12 from a full codebase audit; last revised 2026-09-14 (P6 added).
|
||||
> v1 items (P0-1 through P2-7) are ALL DONE.
|
||||
> Current state: 1539 tests, 86.55% statement coverage, 0 ESLint errors, 173 warnings.
|
||||
> NOTE: the "Current Health Snapshot" below is HISTORICAL (2026-08-12 audit snapshot),
|
||||
> kept for trend reference — re-run the audit before quoting these numbers.
|
||||
> Snapshot values (not current): 1539 tests, 86.55% statement coverage, 0 ESLint errors, 173 warnings.
|
||||
|
||||
## Current Health Snapshot
|
||||
- **Tests:** 1539 passing across 63 suites
|
||||
@@ -257,7 +259,7 @@
|
||||
- **impact:** Users set a disk budget (e.g., "DashCaddy gets 20GB") and the system auto-manages cleanup. The #1 reason people abandon self-hosting is disk filling up silently. This solves it.
|
||||
|
||||
### DC-102: One-click deploy should auto-generate Caddyfile entry + DNS record
|
||||
- **status:** already done (DiskSpaceMonitor)
|
||||
- **status:** pending (prior "already done (DiskSpaceMonitor)" annotation was a mismatched status note — DiskSpaceMonitor is a DC-101 disk-budget component, not a deploy-chain implementation; the deploy chain itself is not wired)
|
||||
- **details:** When a user deploys an app from the catalog, DashCaddy should automatically: (1) Create the Docker container, (2) Add a Caddyfile reverse_proxy block with TLS for `appname.tld`, (3) Create a DNS record pointing to the host, (4) Reload Caddy, (5) Add the service to the dashboard with health check. Currently steps 2-4 are manual. Fix: add a `deployApp(serviceId, options)` function that orchestrates the full chain. The Caddyfile generation can use the admin API (POST to :2019) so no file editing needed. DNS record creation uses the existing Technitium/Cloudflare DNS provider integration. Effort: ~4 hr.
|
||||
- **impact:** This is THE core value proposition. Without this, DashCaddy is just Portainer with extra steps. With this, it's a self-hosting platform.
|
||||
|
||||
@@ -293,6 +295,115 @@
|
||||
|
||||
---
|
||||
|
||||
## P6 — Shipdeck era: cross-platform & barrier removal (added 2026-09-14, Sami directive)
|
||||
|
||||
> Source: "further improve DashCaddy and remove barriers to quality usage of it
|
||||
> on all platforms including PC, Mac and Linux" — planned alongside the Shipdeck
|
||||
> v0 landing (`shipdeck/docs/SPEC.md` in the shipdeck repo, "Definition of done
|
||||
> (v0) — MET 2026-09-14": hello-world on samihost, build → systemd active →
|
||||
> caddy gate (tailnet 200 / public 403) → DNS on DNS2+DNS1 → HTTP health 200 →
|
||||
> journal row, verified rollback). The Shipdeck SPEC names DashCaddy-family use:
|
||||
> "the
|
||||
> deploy engine under the DashCaddy family (DashCaddy panel drives the CLI)";
|
||||
> these items wire that in. Build order: Lane A deployment (DC-109–112) →
|
||||
> Lane B onboarding (DC-113–115) → Lane C platform parity (DC-116–119).
|
||||
>
|
||||
> **Lane acceptance criteria (lane-level outcomes; a lane is done when these hold):**
|
||||
> - Lane A: on a Linux/systemd host where Docker is absent or unused, a real
|
||||
> service completes a fresh shipdeck deploy, one in-place update, and one
|
||||
> rollback — each verified green. Docker regression criteria (must all hold
|
||||
> after each lane item): existing Docker services still deploy/update/roll
|
||||
> back through the unchanged Docker path; existing services.json configs
|
||||
> load without migration errors; the full Jest suite passes at or above the
|
||||
> current gate. Secrets are never logged. This lane owns the
|
||||
> rollback-failure requirement: DC-112 must auto-rollback and alert on
|
||||
> failed post-update health.
|
||||
> - Lane B: on a fresh environment (new browser profile / clean VM), the
|
||||
> doctor detects each seeded environment fault, the auth helper names the
|
||||
> failed hop, and the update nudge stays silent when current.
|
||||
> - Lane C: every parity claim is CI-proven per OS (build + boot + smoke),
|
||||
> not grep-audited.
|
||||
|
||||
### DC-109: Native (Docker-free) service runtime — services gain `runtime: docker|native`
|
||||
- **status:** pending
|
||||
- **details:** Extend the service model with a runtime field. `docker` = today's behavior, unchanged. `native` = the Shipdeck pipeline: local build → tarball → scp → `/opt/<name>/releases/<epoch>/` + `current` symlink → systemd unit → Caddy block → DNS → verify → rollback. All implemented and DoD-verified in Shipdeck v0 (`shipdeck/docs/SPEC.md` — "Definition of done (v0) — MET 2026-09-14": hello-world on samihost, tailnet 200 / public 403, DNS on DNS2+DNS1, journal row, verified rollback). A host running only native services needs NO Docker. **Scope note: DC-109–112 initially target remote Linux/systemd hosts; local macOS/Windows native service parity arrives via DC-117.** Effort: ~6 hr (services.json schema + deploy routing + status surfacing).
|
||||
- **impact:** Removes the largest install dependency identified in this lane's analysis (local Docker Desktop) for PC/Mac users deploying to a remote server; native rollback is one command instead of `docker build` on the VPS.
|
||||
|
||||
### DC-110: Installer "remote server" mode — SSH target, zero local dependencies
|
||||
- **status:** pending
|
||||
- **details:** The Electron installer asks: this machine (classic 5-step wizard, Docker mode) or remote server (SSH host + key, Shipdeck mode). Remote mode skips the Docker/Caddy dependency checks entirely — it configures the remote host and prints the dashboard URL. This is the Mac unlock: no Docker Desktop account, no local engine, works from any laptop. Single-host seed of DC-108 (fleet). Open design points to settle at build time: whether remote mode also provisions remote Caddy/DNS or guides the operator through them, SSH host-key verification policy, and secret-handling (keys never logged, never stored plaintext beyond the user's chosen location). Effort: ~5 hr.
|
||||
- **impact:** Turns "install DashCaddy" from a multi-step dependency hunt into a short wizard; removes the largest single install dependency (local Docker) for non-Linux users.
|
||||
|
||||
### DC-111: DashCaddy dogfoods its own distribution via Shipdeck (native self-host path)
|
||||
- **status:** pending
|
||||
- **details:** Publish a native (non-Docker) DashCaddy flavor: release tarball + generated systemd unit + `current` symlink swap, deployed by Shipdeck. `start.sh` stays for the Docker flavor; the native flavor makes updates a symlink swap instead of `docker build` on the user's VPS. Same release feed (version.json + `revoked` kill switch). Effort: ~4 hr.
|
||||
- **impact:** Installs DashCaddy on hosts without Docker; dogfoods the native path we are selling.
|
||||
|
||||
### DC-112: Updater v2 — release-dir + symlink-swap updates for the native engine
|
||||
- **status:** pending
|
||||
- **details:** Generalize the self-updater shipped in DashCaddy v1.16.0 to the native flavor. Verifiable source of the existing contract: `dashcaddy-api/src/docker/self-updater.js:531` relative to the production-tree root `/opt/dashcaddy` — 30-min release-feed poll (`CHECK_INTERVAL: 30 * 60 * 1000` at line 24), channel selection (`CHANNEL` at line 35), `"revoked": true` kill switch (that line), update-stamp on frontend deploys — written by the host-side `scripts/dashcaddy-update.sh` helper which the self-updater orchestrates (verbatim excerpts, live stamp file, and sync-gate capture in `DC-P6-EVIDENCE.md`, E1/E6); the deploy/rollback flow is also documented in the `dashcaddy-ops` skill, "Self-updater (v1.16.0+, DC-122)" section). Native flavor: download tarball → new release dir → swap `current` → restart → health check → auto-rollback on failed health. Docker path untouched. Effort: ~5 hr.
|
||||
- **impact:** Native installs get the same hands-off updates and rollback safety Docker installs already have.
|
||||
|
||||
### DC-113: First-run doctor — preflight checks + one-click fixes
|
||||
- **status:** pending
|
||||
- **details:** One screen at first run (and from Help): Docker reachable? Caddy binary + admin port? ports 80/443 free? DNS resolvable? disk space? Each check shows fix instructions or a one-click fix where safe. Kills the "blank page on gated service" support class (documented failure mode). Effort: ~4 hr.
|
||||
- **impact:** Support experience to date (DashCaddy sessions 2026-05→09) has been dominated by environment/config issues rather than code bugs; the doctor turns that class into self-service.
|
||||
|
||||
### DC-114: "Why am I seeing this?" helper on the TOTP/auth gate
|
||||
- **status:** pending
|
||||
- **details:** The auth gate is a recurring confusion point (documented in the dashcaddy skill reference `totp-session-ip-key-inconsistency.md`, including the operator report "I keep providing a code and it doesn't work"). Login page gets inline diagnostics: which hop failed, cookie status, IP-consistency note, retry guidance. Server returns structured reason codes instead of bare 401. Effort: ~3 hr.
|
||||
- **impact:** Converts the documented auth-gate drop-off case into a guided flow.
|
||||
|
||||
### DC-115: Update nudge in the dashboard
|
||||
- **status:** pending
|
||||
- **details:** Footer badge comparing running version vs latest release feed; links to the update flow; dismissible; silent when current. The public version endpoint is verified in the live tree: `/api/v1/version` is in `PUBLIC_ROUTES` (`src/utilities/middleware.js`) and wired at startup (`src/app.js`). Latest-version source = the same release feed the self-updater polls (v1.16.0 contract). Effort: ~2 hr.
|
||||
- **impact:** Users running months-old builds file phantom bugs; the nudge keeps fleets current.
|
||||
|
||||
### DC-116: Podman as a supported container runtime
|
||||
- **status:** pending
|
||||
- **details:** Podman speaks Docker's socket API, so most DashCaddy container paths work against it with runtime detection + docs + a CI smoke test (rootless/quadlet notes included). Positions DashCaddy for orgs that cannot run Docker Desktop (licensing) and answers the "Docker vs open-source alternatives" wave with support instead of migration. Effort: ~4 hr.
|
||||
- **impact:** Business-friendly runtime choice; removes licensing objections in the sellable tier.
|
||||
|
||||
### DC-117: Service-control abstraction (systemd/launchd/Windows service) + per-OS static Pylon
|
||||
- **status:** pending
|
||||
- **details:** One service-control API over systemctl / launchd / sc.exe; Pylon ships as a single static agent per OS (no Node runtime required on managed hosts). `platform-paths.js` stays the single source of truth for paths (v1.12.0 lesson). Effort: ~8 hr.
|
||||
- **impact:** True cross-platform management, not Linux-with-caveats.
|
||||
|
||||
### DC-118: Mac Gatekeeper trust path — electron-builder native signing + notarization
|
||||
- **status:** pending
|
||||
- **details:** The Linux-built .dmg/.zip are unsigned → macOS Gatekeeper blocks/scare-warns on first open, and NO lightweight measure removes that friction: **ad-hoc signing does not establish developer identity and does not satisfy Gatekeeper distribution trust** (needs ~$99/yr Apple Developer Program). The fix: **electron-builder's built-in mac signing + notarization** — it signs nested frameworks/helpers with entitlements before the outer app (never hand-rolled `codesign --deep`) and submits notarization itself. Requires `electron-builder >= 24` (verify the version pinned in `dashcaddy-installer/package.json` at implementation time).
|
||||
Implementation shape (config, not a hand-written script — the script gets written and exercised IN this item's PR where a `macos-latest` runner can prove it):
|
||||
```js
|
||||
// electron-builder.config.js (mac section) — shape valid for electron-builder 24.x–26.x.
|
||||
// PIN the actual major against dashcaddy-installer/package.json at implementation time;
|
||||
// if the pinned major is >= 27, migrate per its mac.sign/notarize schema change before use.
|
||||
mac: {
|
||||
identity: "Developer ID Application: <name> (${TEAMID})",
|
||||
hardenedRuntime: true,
|
||||
gatekeeperAssess: true,
|
||||
entitlements: "build/entitlements.mac.plist",
|
||||
notarize: true, // auto notarize + staple on CI (24.x–26.x shape)
|
||||
forceCodeSigning: true, // FATAL on missing credentials — no silent unsigned artifacts
|
||||
}
|
||||
```
|
||||
CI env (Actions secrets only): `CSC_LINK` (the base64-decoded .p12 file path) + `CSC_KEY_PASSWORD` (the .p12's password) — with a CSC_LINK p12, electron-builder imports it into its OWN temporary keychain internally, so the PR must NOT hand-roll keychain lifecycle (no custom create/unlock/partition-list code); notarization uses `APPLE_ID` + `APPLE_APP_SPECIFIC_PASSWORD` + `APPLE_TEAM_ID`.
|
||||
**Acceptance criteria (this item is done only when all pass on a real `macos-latest` run):**
|
||||
1. `electron-builder --mac` exits 0 with signing + notarization enabled.
|
||||
2. Produced `.dmg`: `xcrun stapler validate <dmg>` passes and `spctl -a -t open --context context:primary-signature-id -v <dmg>` reports accepted.
|
||||
3. Produced `.zip`: extract it, then run `spctl -a -t exec -v <extracted .app>` on the contained app — must report accepted. Stapling is per-bundle: the `.app` inside the ZIP carries electron-builder's staple; the ZIP container itself cannot be stapled, and Gatekeeper on macOS 12+ re-queries Apple's notarization service online at first open to assess the signed `.app` inside.
|
||||
4. Notary submission id logged; on failure, `xcrun notarytool log <id> …` output is attached before any retry.
|
||||
5. First-open gate on a clean macOS VM must exercise the real download path with quarantine applied: download via a browser, OR confirm/add the xattr explicitly after any non-browser transfer (`xattr -w com.apple.quarantine "0081;00000000;Safari;" <file>` — do NOT rely on plain `curl`/`scp` to set it; macOS may not apply quarantine to CLI-downloaded files). First open then shows no Gatekeeper block.
|
||||
Drafting-review pitfalls from the 2026-09-14 adversarial rounds are HISTORICAL and inapplicable to this electron-builder approach (they applied to an earlier hand-rolled shell-script draft: keychain passwords, `mktemp -u`, search-list restore, filename gating — all now handled by electron-builder's internal keychain management). The version-validation rule stands: at implementation, confirm the pinned electron-builder major's actual `mac.sign`, `notarize`, and `forceCodeSigning` schema against its docs — do not trust the broad 24.x–26.x shape above without checking.
|
||||
The Linux .dmg build this slots into is documented in `dashcaddy-installer/BUILD_GUIDE.md` (libguestfs HFS+ volume + libdmg-hfsplus UDZO). Effort: ~2 hr once enrolled (+$99/yr Apple Developer Program).
|
||||
- **impact:** Today the first Mac impression is a security warning; the trust path must be fixed before paid acquisition, and only real signing + notarization does it.
|
||||
|
||||
### DC-119: Cross-platform CI matrix — boot it on all 3 OSes per release
|
||||
- **status:** pending
|
||||
- **details:** Per release: build API + installer on Windows/macOS/Linux runners, boot the API, run smoke probes (version + health), run the installer's dependency-checker in report mode. Replaces grep-audits with runtime proof — matches the reproducibility principle (Sami 2026-06: "other people can do the same things and expect reproducibility"). Effort: ~6 hr.
|
||||
- **impact:** Platform-parity claims become tested facts, not hopes.
|
||||
|
||||
---
|
||||
|
||||
## Summary by Priority
|
||||
|
||||
| Priority | Count | Effort | Theme |
|
||||
@@ -305,4 +416,5 @@
|
||||
| P3.5 | 9 (DC-086–094) | ~14.5 hr | Operational maturity |
|
||||
| P4 | 6 (DC-095–100) | ~16.5 hr | Advanced features |
|
||||
| P5 | 8 (DC-101–108) | ~29 hr | Product vision: self-hosting platform |
|
||||
| **Total** | **47** | **~110.5 hr** | |
|
||||
| P6 | 11 (DC-109–119) | ~49 hr | Shipdeck era: cross-platform & barrier removal |
|
||||
| **Total** | **58** | **~159.5 hr** | |
|
||||
|
||||
Reference in New Issue
Block a user