betterNAS/packages/contracts/openapi/betternas.v1.yaml
Harivansh Rathi b5f8ea9c52 Make control-plane the real mount authority
Split node enrollment from export sync and issue Finder-compatible DAV
credentials so the stack proves the real backend seam before any web UI
consumes it.
2026-04-01 17:46:50 +00:00

392 lines
8.8 KiB
YAML

openapi: 3.1.0
info:
title: betterNAS Foundation API
version: 0.1.0
summary: Foundation contract for node registration, export metadata, and profile issuance.
servers:
- url: http://localhost:8081
paths:
/health:
get:
operationId: getControlPlaneHealth
responses:
"200":
description: Control-plane health
/version:
get:
operationId: getControlPlaneVersion
responses:
"200":
description: Control-plane version
/api/v1/nodes/register:
post:
operationId: registerNode
security:
- NodeBootstrapToken: []
- NodeToken: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NodeRegistrationRequest"
responses:
"200":
description: Registered node
headers:
X-BetterNAS-Node-Token:
description: Returned when a node is first registered or migrated to node-scoped auth.
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/NasNode"
"401":
description: Unauthorized
/api/v1/nodes/{nodeId}/heartbeat:
post:
operationId: recordNodeHeartbeat
security:
- NodeToken: []
parameters:
- in: path
name: nodeId
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NodeHeartbeatRequest"
responses:
"204":
description: Heartbeat accepted
"401":
description: Unauthorized
/api/v1/nodes/{nodeId}/exports:
put:
operationId: syncNodeExports
security:
- NodeToken: []
parameters:
- in: path
name: nodeId
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NodeExportsRequest"
responses:
"200":
description: Export inventory accepted
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/StorageExport"
"401":
description: Unauthorized
/api/v1/exports:
get:
operationId: listExports
security:
- ClientToken: []
responses:
"200":
description: Export list
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/StorageExport"
"401":
description: Unauthorized
/api/v1/mount-profiles/issue:
post:
operationId: issueMountProfile
security:
- ClientToken: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MountProfileRequest"
responses:
"200":
description: Mount profile
content:
application/json:
schema:
$ref: "#/components/schemas/MountProfile"
"401":
description: Unauthorized
/api/v1/cloud-profiles/issue:
post:
operationId: issueCloudProfile
security:
- ClientToken: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CloudProfileRequest"
responses:
"200":
description: Cloud profile
content:
application/json:
schema:
$ref: "#/components/schemas/CloudProfile"
"401":
description: Unauthorized
components:
securitySchemes:
ClientToken:
type: http
scheme: bearer
description: Bearer token required for export listing and profile issuance.
NodeBootstrapToken:
type: http
scheme: bearer
description: Bearer token required to register a new node before it receives a node-scoped token.
NodeToken:
type: http
scheme: bearer
description: Bearer token scoped to a previously registered node.
schemas:
NasNode:
type: object
required:
- id
- machineId
- displayName
- agentVersion
- status
- lastSeenAt
- directAddress
- relayAddress
properties:
id:
type: string
machineId:
type: string
displayName:
type: string
agentVersion:
type: string
status:
type: string
enum: [online, offline, degraded]
lastSeenAt:
type: string
directAddress:
type:
- string
- "null"
relayAddress:
type:
- string
- "null"
StorageExport:
type: object
required:
- id
- nasNodeId
- label
- path
- protocols
- capacityBytes
- tags
properties:
id:
type: string
nasNodeId:
type: string
label:
type: string
path:
type: string
mountPath:
type: string
protocols:
type: array
items:
type: string
enum: [webdav]
capacityBytes:
type:
- integer
- "null"
tags:
type: array
items:
type: string
MountProfile:
type: object
required:
- id
- exportId
- protocol
- displayName
- mountUrl
- readonly
- credential
properties:
id:
type: string
exportId:
type: string
protocol:
type: string
enum: [webdav]
displayName:
type: string
mountUrl:
type: string
readonly:
type: boolean
credential:
$ref: "#/components/schemas/MountCredential"
MountCredential:
type: object
required:
- mode
- username
- password
- expiresAt
properties:
mode:
type: string
enum: [basic-auth]
username:
type: string
password:
type: string
expiresAt:
type: string
CloudProfile:
type: object
required:
- id
- exportId
- provider
- baseUrl
- path
properties:
id:
type: string
exportId:
type: string
provider:
type: string
enum: [nextcloud]
baseUrl:
type: string
path:
type: string
StorageExportInput:
type: object
required:
- label
- path
- protocols
- capacityBytes
- tags
properties:
label:
type: string
path:
type: string
mountPath:
type: string
protocols:
type: array
items:
type: string
enum: [webdav]
capacityBytes:
type:
- integer
- "null"
tags:
type: array
items:
type: string
NodeRegistrationRequest:
type: object
required:
- machineId
- displayName
- agentVersion
- directAddress
- relayAddress
properties:
machineId:
type: string
displayName:
type: string
agentVersion:
type: string
directAddress:
type:
- string
- "null"
relayAddress:
type:
- string
- "null"
NodeExportsRequest:
type: object
required:
- exports
properties:
exports:
type: array
items:
$ref: "#/components/schemas/StorageExportInput"
NodeHeartbeatRequest:
type: object
required:
- nodeId
- status
- lastSeenAt
properties:
nodeId:
type: string
status:
type: string
enum: [online, offline, degraded]
lastSeenAt:
type: string
MountProfileRequest:
type: object
required:
- exportId
properties:
exportId:
type: string
CloudProfileRequest:
type: object
required:
- userId
- exportId
- provider
properties:
userId:
type: string
exportId:
type: string
provider:
type: string
enum: [nextcloud]