6.9 KiB
betterNAS Architecture Contract
This file is the canonical contract for the repository.
If the planning docs, scaffold code, or future tasks disagree, this file and
packages/contracts win.
Product default
betterNAS is self-hosted first.
For the current product shape, the user should be able to run the whole stack on their NAS machine:
node-serviceserves the real files over WebDAVcontrol-serverowns auth, nodes, exports, grants, and mount profilesweb control planeis the browser UI over the control-server- the local device mounts an issued WebDAV URL in Finder
Optional hosted deployments can come later. Optional Nextcloud integration can come later.
The core system
betterNAS canonical contract
self-hosted on user's NAS
+--------------------------------------+
| [2] control-server |
| system of record |
| auth / nodes / exports / grants |
| mount sessions / audit |
+------------------+-------------------+
|
v
+--------------------------------------+
| [1] node-service |
| WebDAV export runtime |
| real file bytes |
+------------------+-------------------+
^
|
+------------------+-------------------+
| [3] web control plane |
| onboarding / management / mount UX |
+------------------+-------------------+
^
|
user browser
user local device
|
+-----------------------------------------------> Finder mount
via issued WebDAV URL
[4] optional cloud adapter
|
+--> secondary browser/mobile/share layer
not part of the core mount path
Non-negotiable rules
control-serveris the system of record.node-serviceserves the bytes.web control planeis a UI overcontrol-server, not a second policy backend.- The main data path should be
local device <-> node-servicewhenever possible. control-servershould issue access, grants, and mount profiles. It should not become the default file proxy.- The self-hosted stack should work without Nextcloud.
- Nextcloud, if used, is an optional adapter and secondary surface.
Canonical sources of truth
Use these in this order:
docs/architecture.mdfor boundaries, ownership, and delivery rulespackages/contractsfor machine-readable types, schemas, and route constants- the part docs:
Repo lanes
The monorepo is split into these primary implementation lanes:
The first three are core. apps/nextcloud-app is optional and should not drive
the main architecture.
The contract surface we need first
The first shared contract set should cover only the seams needed for the self-hosted mount flow.
Node-service -> control-server
- node registration
- node heartbeat
- export inventory via a dedicated sync endpoint
Web control plane -> control-server
- auth/session bootstrapping
- list nodes and exports
- issue mount profile
- issue share or cloud profile later
For v1, the same betterNAS username and password should be used across the web UI, node enrollment, and Finder WebDAV login.
Local device -> control-server
- fetch mount instructions
- receive issued WebDAV URL plus the betterNAS account username
- username
- expiresAt
Initial backend route sketch
The first backend contract should stay narrow:
POST /api/v1/nodes/registerPOST /api/v1/nodes/{nodeId}/heartbeatPUT /api/v1/nodes/{nodeId}/exportsGET /api/v1/exportsPOST /api/v1/mount-profiles/issue
Control-server internal
- health
- version
- the first domain entities:
NasNodeStorageExportAccessGrantMountProfileAuditEvent
Parallel work boundaries
| Part | Owns | May read | Must not own |
|---|---|---|---|
| node-service | NAS runtime, WebDAV serving, export reporting | contracts, control-server docs | product policy |
| control-server | domain model, grants, profile issuance, registry | everything | direct file serving by default |
| web control plane | onboarding, node/export management, mount UX | contracts, control-server docs | source of truth |
| optional adapter | Nextcloud mapping and cloud surfaces | contracts, control-server docs | core mount path |
The shared write surface across parts should stay narrow:
packages/contracts- this file when architecture changes
Verification loop
This is the main loop every near-term task should support.
[node-service]
serves a WebDAV export
|
v
[control-server]
registers the node and export
issues a mount profile
|
v
[web control plane]
shows the export and mount action
|
v
[local device]
mounts the issued WebDAV URL in Finder
If a task does not make one of those steps more real, it is probably too early.
Definition of done for the current foundation
The current foundation is in good shape when:
- the self-hosted stack boots locally
- the control-server can represent nodes, exports, grants, and mount profiles
- the node-service serves a real WebDAV export
- the web control plane can expose the mount flow
- a local Mac can mount the export in Finder
Rules for future tasks and agents
- No part may invent private request or response shapes for shared flows.
- Contract changes must update
packages/contractsfirst. - Architecture changes must update this file in the same change.
- Additive contract changes are preferred over breaking ones.
- Prioritize the self-hosted mount loop before optional cloud/mobile work.