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.
6.8 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
Local device -> control-server
- fetch mount instructions
- receive issued WebDAV URL and standard WebDAV credentials
- username
- password
- 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.