feat: RBAC, atomic deployments, fleet backups, and licensing (Pro) (#185)

* feat: add RBAC viewer accounts, atomic deployments, and fleet-wide backups (Pro)

Introduces three Pro-tier features:

- RBAC: Multi-user system with admin/viewer roles, user management UI,
  automatic migration from single-admin credentials, viewer restrictions
  across the entire UI (read-only editor, hidden action buttons)

- Atomic Deployments: Pre-deploy file backup to .sencho-backup/, automatic
  rollback on health probe failure, manual rollback button, health probes
  added to stack updates, webhook-triggered deploys use atomic rollback

- Fleet-Wide Backups: Point-in-time snapshots of compose files across all
  nodes (local + remote), stored centrally in SQLite, per-stack restore
  with optional redeploy, graceful handling of offline nodes

* fix(settings): use correct ProGate prop name in UsersSection

* fix(settings): remove unused isPro prop from UsersSection

* fix(auth): fetch user info after login and setup so isAdmin is set correctly

* feat(pricing): revise pricing strategy and enforce variant-based seat limits

Raise Personal Pro from $49/yr to $69/yr with 3 viewer seats (up from 1).
Add $15/mo billing option for Team Pro. Mark lifetime pricing as a
90-day early-adopter offer. Store Lemon Squeezy variant_name on
activation/validation and enforce seat limits server-side per variant.

* feat(licensing): add Lemon Squeezy checkout, webhook, and billing portal integration

Server-side checkout URL generation (POST /api/checkout) with admin email
pre-fill and instance_id custom data. HMAC-SHA256 verified webhook endpoint
(POST /api/webhooks/lemonsqueezy) handling order, subscription, and payment
lifecycle events for automatic license activation. Customer billing portal
link stored from webhook events and exposed via GET /api/billing/portal.
In-app checkout buttons in Settings with manual license key fallback.

* fix(licensing): exempt Lemon Squeezy webhook from auth middleware

The catch-all auth middleware on /api/* was blocking the public webhook
endpoint. Added /webhooks/lemonsqueezy to the exemption list alongside
/auth/* and /webhooks/:id/trigger.

* feat(pricing): update pricing to final live rates

Personal Pro: $7.99/month, $69.99/year, $249 lifetime.
Team Pro: $49.99/month, $499.99/year, $1,499 lifetime.
Added personal_monthly checkout variant across backend, frontend, and website.

* refactor(licensing): remove server-side checkout/webhook for self-hosted model

Sencho is self-hosted — each user runs their own instance, so there is
no central server to receive webhooks or hold the store API key. Replaced
in-app checkout buttons with a "View Pricing" redirect to sencho.io and
kept manual license key activation as the primary flow.

- Delete LemonSqueezyService (checkout, webhook, HMAC verification)
- Remove POST /api/checkout, GET /api/billing/portal, POST /api/webhooks/lemonsqueezy
- Remove raw body parser and auth exemption for webhook route
- Remove all LEMONSQUEEZY_* env vars from .env.example
- Replace checkout buttons in SettingsModal with single "View Pricing" button
- Simplify LicenseContext checkout to open sencho.io pricing page
- Update licensing docs to reflect website-based purchase flow

* chore: normalize em-dashes to hyphens across codebase (linter)

* chore: remove accidentally tracked directories from index
This commit is contained in:
Anso
2026-03-26 21:58:24 -04:00
committed by GitHub
parent 269ea6fe53
commit 32a7d53b2b
54 changed files with 721 additions and 543 deletions
+6 -6
View File
@@ -41,21 +41,21 @@ volumes:
```
<Warning>
Without a persistent data mount, Sencho will lose all configuration including registered nodes, alerts, and settings every time the container restarts.
Without a persistent data mount, Sencho will lose all configuration - including registered nodes, alerts, and settings - every time the container restarts.
</Warning>
### Compose directory the 1:1 path rule
### Compose directory - the 1:1 path rule
<Warning>
This is the most common source of deployment problems. Read carefully.
</Warning>
When Sencho runs `docker compose up`, it does so on your **host machine**. Docker resolves relative volume paths in your Compose files relative to the **host** path of the stack directory not the path inside the Sencho container.
When Sencho runs `docker compose up`, it does so on your **host machine**. Docker resolves relative volume paths in your Compose files relative to the **host** path of the stack directory - not the path inside the Sencho container.
**The rule:** Mount your Compose directory at the **exact same path** inside the container as it exists on your host.
```yaml
# ✅ Correct host path matches container path
# ✅ Correct - host path matches container path
volumes:
- /home/boris/docker:/home/boris/docker
environment:
@@ -63,7 +63,7 @@ environment:
```
```yaml
# ❌ Wrong paths differ, relative volumes will break
# ❌ Wrong - paths differ, relative volumes will break
volumes:
- /home/boris/docker:/app/compose
environment:
@@ -158,4 +158,4 @@ labels:
## First boot
After starting Sencho, open it in your browser. If no admin account exists yet, you'll be taken to a setup screen to create one. This only appears once subsequent visits go directly to the login page.
After starting Sencho, open it in your browser. If no admin account exists yet, you'll be taken to a setup screen to create one. This only appears once - subsequent visits go directly to the login page.
+13 -13
View File
@@ -3,7 +3,7 @@ title: Introduction
description: What Sencho is and why you might want it.
---
Sencho is a self-hosted Docker Compose management dashboard. It gives you a clean web UI to deploy, manage, and monitor your Docker Compose stacks locally or across multiple remote servers without touching a terminal.
Sencho is a self-hosted Docker Compose management dashboard. It gives you a clean web UI to deploy, manage, and monitor your Docker Compose stacks - locally or across multiple remote servers - without touching a terminal.
<Frame>
<img src="/images/dashboard/dashboard-overview.png" alt="Sencho dashboard showing system stats and container metrics" />
@@ -11,9 +11,9 @@ Sencho is a self-hosted Docker Compose management dashboard. It gives you a clea
## Key concepts
- **Stacks** a Docker Compose project living in your `COMPOSE_DIR`. Sencho treats each subdirectory as a stack.
- **Nodes** a Sencho instance. Your local machine is always the default node. Add remote nodes by pointing Sencho at another Sencho instance's API URL.
- **Resources** images, volumes, and networks that belong to your stacks (managed) or exist outside them (external/unused).
- **Stacks** - a Docker Compose project living in your `COMPOSE_DIR`. Sencho treats each subdirectory as a stack.
- **Nodes** - a Sencho instance. Your local machine is always the default node. Add remote nodes by pointing Sencho at another Sencho instance's API URL.
- **Resources** - images, volumes, and networks that belong to your stacks (managed) or exist outside them (external/unused).
<Note>
Sencho never accesses remote servers directly via SSH or Docker TCP. Remote management works by proxying API requests to another running Sencho instance.
@@ -21,12 +21,12 @@ Sencho is a self-hosted Docker Compose management dashboard. It gives you a clea
## What you can do
- **Deploy and control stacks** create, start, stop, restart, and delete Compose stacks with one click
- **Edit files in-browser** full Monaco editor for `compose.yaml` and `.env` files
- **Monitor in real-time** live CPU, RAM, disk, and network stats with historical charts
- **Stream logs** tail container logs individually or aggregate all stacks in one view
- **Manage resources** browse, filter, and prune Docker images, volumes, and networks
- **Deploy from the App Store** one-click deployment from a curated template registry
- **Run a host console** interactive terminal on the host OS directly in the browser
- **Set alerts** threshold-based notifications via Discord, Slack, or any webhook
- **Manage multiple servers** add remote Sencho instances as nodes and switch between them seamlessly
- **Deploy and control stacks** - create, start, stop, restart, and delete Compose stacks with one click
- **Edit files in-browser** - full Monaco editor for `compose.yaml` and `.env` files
- **Monitor in real-time** - live CPU, RAM, disk, and network stats with historical charts
- **Stream logs** - tail container logs individually or aggregate all stacks in one view
- **Manage resources** - browse, filter, and prune Docker images, volumes, and networks
- **Deploy from the App Store** - one-click deployment from a curated template registry
- **Run a host console** - interactive terminal on the host OS directly in the browser
- **Set alerts** - threshold-based notifications via Discord, Slack, or any webhook
- **Manage multiple servers** - add remote Sencho instances as nodes and switch between them seamlessly
+4 -4
View File
@@ -29,10 +29,10 @@ Open `http://localhost:3000` in your browser. On first boot you'll be prompted t
## Important: the 1:1 path rule
The `-v /opt/compose:/app/compose` mount above uses a simplified path for illustration. In practice, you must mount your compose directory at the **same path** inside and outside the container. See the [Configuration guide](/getting-started/configuration#compose-directory-the-11-path-rule) for details this is the most common setup mistake.
The `-v /opt/compose:/app/compose` mount above uses a simplified path for illustration. In practice, you must mount your compose directory at the **same path** inside and outside the container. See the [Configuration guide](/getting-started/configuration#compose-directory-the-11-path-rule) for details - this is the most common setup mistake.
## Next steps
- [Configuration](/getting-started/configuration) full environment variable reference, reverse proxy setup
- [Stack Management](/features/stack-management) create and deploy your first stack
- [Multi-Node](/features/multi-node) add a remote server to manage from this dashboard
- [Configuration](/getting-started/configuration) - full environment variable reference, reverse proxy setup
- [Stack Management](/features/stack-management) - create and deploy your first stack
- [Multi-Node](/features/multi-node) - add a remote server to manage from this dashboard