mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-10 18:56:53 +00:00
feat(nodes): add capability-based node compatibility negotiation (#350)
* feat(nodes): add capability-based node compatibility negotiation Each Sencho instance now exposes /api/meta with its version and supported capabilities. When the user switches nodes, the frontend fetches this metadata and disables features the remote node doesn't support via a CapabilityGate overlay. Version is shown in the node switcher dropdown and connection test results. - Backend: CapabilityRegistry with static capability list and fetchRemoteMeta helper - Backend: /api/meta (public) and /api/nodes/:id/meta (auth) endpoints - Frontend: NodeContext enhanced with per-node meta caching (5min TTL) - Frontend: CapabilityGate component with typed Capability union - Frontend: 13 features wrapped with capability gates - Docs: node-compatibility.mdx + OpenAPI spec updates * fix(nodes): revert to require() for package.json version reading The static import fails in the Docker multi-stage build because the root package.json is not copied into the backend-builder stage. The require() call resolves at runtime when the file is available.
This commit is contained in:
+6
-3
@@ -102,6 +102,7 @@
|
||||
"features/global-observability",
|
||||
"features/host-console",
|
||||
"features/multi-node",
|
||||
"features/node-compatibility",
|
||||
"features/fleet-view",
|
||||
"features/stack-labels",
|
||||
"features/alerts-notifications",
|
||||
@@ -145,9 +146,10 @@
|
||||
"pages": [
|
||||
"api-reference/overview",
|
||||
{
|
||||
"group": "Health",
|
||||
"group": "Health & Meta",
|
||||
"pages": [
|
||||
"GET /api/health"
|
||||
"GET /api/health",
|
||||
"GET /api/meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -210,7 +212,8 @@
|
||||
"GET /api/nodes/{id}",
|
||||
"PUT /api/nodes/{id}",
|
||||
"DELETE /api/nodes/{id}",
|
||||
"POST /api/nodes/{id}/test"
|
||||
"POST /api/nodes/{id}/test",
|
||||
"GET /api/nodes/{id}/meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: Node Compatibility
|
||||
description: How Sencho handles version differences across nodes and gracefully degrades features that aren't available on older instances.
|
||||
---
|
||||
|
||||
When you manage multiple nodes, each running its own Sencho instance, those instances may be on different versions. A node running v0.28 won't have features that shipped in v0.31. Sencho detects this automatically and disables features that the active node doesn't support — no errors, no broken pages.
|
||||
|
||||
## How it works
|
||||
|
||||
Every Sencho instance exposes a `/api/meta` endpoint that returns its version and a list of **capabilities** — feature flags describing what that instance supports. When you switch to a node, your primary instance fetches this metadata and caches it for 5 minutes.
|
||||
|
||||
Features that require a capability the active node doesn't have are visually dimmed with an explanation overlay. Core features like stack management, containers, and resource monitoring are always available on every Sencho version.
|
||||
|
||||
## What you'll see
|
||||
|
||||
### Version in the node switcher
|
||||
|
||||
The sidebar node switcher shows each node's Sencho version next to its name. If a node is too old to report its version (pre-compatibility era), no version is shown.
|
||||
|
||||
### Disabled features
|
||||
|
||||
When you switch to a node that lacks a capability, the affected feature appears dimmed with a pill overlay explaining why:
|
||||
|
||||
> **Fleet Management** is not available — prod-server is running v0.28.0
|
||||
|
||||
The feature content is still visible (blurred) so you can see what you're missing, but it's non-interactive. Switch to a node that supports the feature, or update the remote node to the latest Sencho version.
|
||||
|
||||
### Connection test details
|
||||
|
||||
When you test a remote node's connection in **Settings > Nodes**, the result now includes the remote Sencho version alongside Docker info, container counts, and system stats.
|
||||
|
||||
## Capability list
|
||||
|
||||
Every Sencho release includes a static list of capabilities. Here are the capabilities tracked as of the current version:
|
||||
|
||||
| Capability | Feature |
|
||||
|-----------|---------|
|
||||
| `stacks` | Stack management (always available) |
|
||||
| `containers` | Container operations (always available) |
|
||||
| `resources` | Resource monitoring (always available) |
|
||||
| `templates` | App Store (always available) |
|
||||
| `global-logs` | Global log viewer (always available) |
|
||||
| `system-stats` | System statistics (always available) |
|
||||
| `fleet` | Fleet management |
|
||||
| `auto-updates` | Auto-update policies |
|
||||
| `labels` | Stack labels |
|
||||
| `webhooks` | Webhooks |
|
||||
| `network-topology` | Network topology view |
|
||||
| `notifications` | Alert notifications |
|
||||
| `notification-routing` | Notification routing rules |
|
||||
| `host-console` | Host console |
|
||||
| `audit-log` | Audit log |
|
||||
| `scheduled-ops` | Scheduled operations |
|
||||
| `sso` | SSO authentication |
|
||||
| `api-tokens` | API token management |
|
||||
| `users` | User management |
|
||||
| `registries` | Private registry management |
|
||||
|
||||
<Note>
|
||||
Capabilities are flag-based, not version-based. Sencho never compares version numbers — it checks whether the remote node explicitly advertises support for a feature. This means the system stays forward-compatible as new features are added.
|
||||
</Note>
|
||||
|
||||
## Handling older nodes
|
||||
|
||||
Nodes running a Sencho version from before the compatibility system was introduced (pre-v0.32) don't have the `/api/meta` endpoint. Sencho handles this gracefully:
|
||||
|
||||
- The version shows as blank in the node switcher
|
||||
- All gated features appear as unavailable on that node
|
||||
- Core features (stacks, containers, resources, logs) work normally
|
||||
- No errors are thrown — the UI degrades cleanly
|
||||
|
||||
The fix is straightforward: update the remote node to the latest Sencho version. See the [upgrade guide](/operations/upgrade) for instructions.
|
||||
|
||||
## Interaction with license tiers
|
||||
|
||||
Some features require both a license tier (Skipper or Admiral) **and** node capability support. When both gates apply:
|
||||
|
||||
1. The license gate is checked first — if you're on the Community tier, you see the upgrade prompt
|
||||
2. If your license covers the feature but the node doesn't support it, you see the compatibility overlay instead
|
||||
|
||||
This means you won't see confusing "upgrade to unlock" messages for features that wouldn't work on the active node anyway.
|
||||
@@ -543,6 +543,33 @@ paths:
|
||||
type: number
|
||||
description: Process uptime in seconds.
|
||||
|
||||
/api/meta:
|
||||
get:
|
||||
operationId: getMeta
|
||||
tags: [Health]
|
||||
summary: Instance metadata
|
||||
description: Returns this Sencho instance's version and list of supported capabilities. No authentication required. Used by nodes to negotiate feature compatibility.
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Instance metadata.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [version, capabilities]
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
description: Sencho version (semver).
|
||||
example: "0.32.0"
|
||||
capabilities:
|
||||
type: array
|
||||
description: List of feature capabilities this instance supports.
|
||||
items:
|
||||
type: string
|
||||
example: ["stacks", "containers", "fleet", "auto-updates", "host-console"]
|
||||
|
||||
# ── Stacks ──────────────────────────────────────────────
|
||||
/api/stacks:
|
||||
get:
|
||||
@@ -1767,6 +1794,39 @@ paths:
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/api/nodes/{id}/meta:
|
||||
get:
|
||||
operationId: getNodeMeta
|
||||
tags: [Nodes]
|
||||
summary: Get node capabilities
|
||||
description: Returns the version and supported capabilities for a specific node. For local nodes, returns this instance's own metadata. For remote nodes, relays the response from the remote instance's `/api/meta` endpoint. Returns `{ version: null, capabilities: [] }` if the remote node is offline or doesn't support the meta endpoint.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Node capability metadata.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [version, capabilities]
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Sencho version of the node, or null if unavailable.
|
||||
example: "0.31.0"
|
||||
capabilities:
|
||||
type: array
|
||||
description: List of feature capabilities the node supports. Empty array if unavailable.
|
||||
items:
|
||||
type: string
|
||||
example: ["stacks", "containers", "fleet"]
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
# ── Fleet ───────────────────────────────────────────────
|
||||
/api/fleet/overview:
|
||||
get:
|
||||
|
||||
Reference in New Issue
Block a user