mirror of
https://github.com/harivansh-afk/betterNAS.git
synced 2026-04-15 06:04:40 +00:00
update docs
This commit is contained in:
parent
c5be520772
commit
5bc24fa99d
11 changed files with 591 additions and 632 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# betterNAS Part 1: NAS Node
|
||||
|
||||
This document describes the software that runs on the actual NAS machine, VM, or workstation that owns the files.
|
||||
This document describes the software that runs on the actual NAS machine, VM,
|
||||
or workstation that owns the files.
|
||||
|
||||
## What it is
|
||||
|
||||
|
|
@ -8,10 +9,11 @@ The NAS node is the machine that actually has the storage.
|
|||
|
||||
It should run:
|
||||
|
||||
- a WebDAV server
|
||||
- a small betterNAS node agent
|
||||
- declarative config via Nix
|
||||
- optional tunnel or relay connection if the machine is not directly reachable
|
||||
- the `node-service`
|
||||
- a WebDAV server surface
|
||||
- export configuration
|
||||
- optional enrollment or heartbeat back to `control-server`
|
||||
- later, a reproducible install path such as Docker or Nix
|
||||
|
||||
It should expose one or more storage exports such as:
|
||||
|
||||
|
|
@ -24,47 +26,38 @@ It should expose one or more storage exports such as:
|
|||
|
||||
- serves the real file bytes
|
||||
- exposes chosen directories over WebDAV
|
||||
- registers itself with the control plane
|
||||
- reports health, identity, and available exports
|
||||
- optionally keeps an outbound connection alive for remote access
|
||||
- reports identity, health, and exports to `control-server`
|
||||
- stays simple enough to self-host on a single NAS box
|
||||
|
||||
## What it should not do
|
||||
|
||||
- own user-facing product logic
|
||||
- decide permissions by itself
|
||||
- become the system of record for shares, devices, or policies
|
||||
- own product policy
|
||||
- decide user access rules by itself
|
||||
- become the system of record for users, grants, or shares
|
||||
|
||||
## Diagram
|
||||
|
||||
```text
|
||||
betterNAS system
|
||||
self-hosted betterNAS stack
|
||||
|
||||
local device <-------> control plane <-------> cloud/web layer
|
||||
| | |
|
||||
| | |
|
||||
+-------------------------+--------------------------+
|
||||
|
|
||||
v
|
||||
+---------------------------+
|
||||
| [THIS DOC] NAS node |
|
||||
|---------------------------|
|
||||
| WebDAV server |
|
||||
| node agent |
|
||||
| exported directories |
|
||||
| optional tunnel/relay |
|
||||
+---------------------------+
|
||||
web control plane ---> control-server ---> [THIS DOC] node-service
|
||||
^ |
|
||||
| |
|
||||
+---------------- user browser ----------+
|
||||
|
||||
local Mac ---------------- Finder mount ----------+
|
||||
```
|
||||
|
||||
## Core decisions
|
||||
|
||||
- The NAS node should be where WebDAV is served from whenever possible.
|
||||
- The control plane should configure access, but file bytes should flow from the node to the user device as directly as possible.
|
||||
- The node should be installable with a Nix module or flake so setup is reproducible.
|
||||
- The node should be installable as one boring runtime on the user's machine.
|
||||
- The node should expose exports, not product semantics.
|
||||
|
||||
## TODO
|
||||
|
||||
- Choose the WebDAV server we will standardize on for the node.
|
||||
- Define the node agent responsibilities and API back to the control plane.
|
||||
- Define the storage export model: path, label, capacity, tags, protocol support.
|
||||
- Define direct-access vs relayed-access behavior.
|
||||
- Define how the node connects to the cloud/web layer for optional Nextcloud integration.
|
||||
- Define the self-hosted install shape: Docker first, Nix second, or both.
|
||||
- Define the node identity and enrollment model.
|
||||
- Define the storage export model: path, label, tags, permissions, capacity.
|
||||
- Define when the node self-registers vs when bootstrap tooling registers it.
|
||||
- Define direct-access vs relay-access behavior for remote use.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
# betterNAS Part 2: Control Plane
|
||||
# betterNAS Part 2: Control Server
|
||||
|
||||
This document describes the main backend that owns product semantics and coordinates the rest of the system.
|
||||
This document describes the main backend that owns product semantics and
|
||||
coordinates the rest of the system.
|
||||
|
||||
## What it is
|
||||
|
||||
The control plane is the source of truth for betterNAS.
|
||||
`control-server` is the source of truth for betterNAS.
|
||||
|
||||
It should own:
|
||||
|
||||
|
|
@ -14,8 +15,7 @@ It should own:
|
|||
- storage exports
|
||||
- access grants
|
||||
- mount profiles
|
||||
- cloud access profiles
|
||||
- audit events
|
||||
- later, share flows and audit events
|
||||
|
||||
## What it does
|
||||
|
||||
|
|
@ -23,35 +23,32 @@ It should own:
|
|||
- tracks which NAS nodes exist
|
||||
- decides who can access which export
|
||||
- issues mount instructions to local devices
|
||||
- coordinates optional cloud/web access
|
||||
- stores the operational model of the whole product
|
||||
- drives the web control plane
|
||||
- stores the operational model of the product
|
||||
|
||||
## What it should not do
|
||||
|
||||
- proxy file bytes unless absolutely necessary
|
||||
- become a bottleneck in the data path
|
||||
- depend on Nextcloud as its system of record
|
||||
- proxy file bytes by default
|
||||
- become the only data path between the Mac and the NAS
|
||||
- depend on Nextcloud as its source of truth
|
||||
|
||||
## Diagram
|
||||
|
||||
```text
|
||||
betterNAS system
|
||||
self-hosted betterNAS stack
|
||||
|
||||
NAS node <---------> [THIS DOC] control plane <---------> local device
|
||||
| | |
|
||||
| | |
|
||||
+---------------------------+-----------------------+-----------+
|
||||
|
|
||||
v
|
||||
cloud/web layer
|
||||
node-service <--------> [THIS DOC] control-server <--------> web control plane
|
||||
^ |
|
||||
| |
|
||||
+----------- Finder mount flow -+
|
||||
```
|
||||
|
||||
## Core decisions
|
||||
|
||||
- The control plane is the product brain.
|
||||
- It should own policy and registry, not storage bytes.
|
||||
- It should stay standalone even if it integrates with Nextcloud.
|
||||
- It should issue access decisions, not act like a file server.
|
||||
- `control-server` is the product brain.
|
||||
- It owns policy and registry, not storage bytes.
|
||||
- It should stay deployable on the user's NAS in the default product shape.
|
||||
- The web UI should remain a consumer of this service, not a second backend.
|
||||
|
||||
## Suggested first entities
|
||||
|
||||
|
|
@ -61,13 +58,12 @@ It should own:
|
|||
- `StorageExport`
|
||||
- `AccessGrant`
|
||||
- `MountProfile`
|
||||
- `CloudProfile`
|
||||
- `AuditEvent`
|
||||
|
||||
## TODO
|
||||
|
||||
- Define the first real domain model and database schema.
|
||||
- Define auth between user device, NAS node, and control plane.
|
||||
- Define the API for mount profiles and access grants.
|
||||
- Define how the control plane tells the cloud/web layer what to expose.
|
||||
- Define direct-access vs relay behavior for unreachable NAS nodes.
|
||||
- Define the first durable database schema.
|
||||
- Define auth between user browser, user device, NAS node, and control-server.
|
||||
- Define the API for node registration, export inventory, and mount issuance.
|
||||
- Define how mount tokens or credentials are issued and rotated.
|
||||
- Define what optional cloud/share integration looks like later.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
# betterNAS Part 3: Local Device
|
||||
|
||||
This document describes the software and user experience on the user's Mac or other local device.
|
||||
This document describes the software and user experience on the user's Mac or
|
||||
other local device.
|
||||
|
||||
## What it is
|
||||
|
||||
The local device layer is how a user actually mounts and uses their NAS.
|
||||
|
||||
It can start simple:
|
||||
It should start simple:
|
||||
|
||||
- Finder + WebDAV mount
|
||||
- manual `Connect to Server`
|
||||
- browser opens the web control plane
|
||||
- user gets a WebDAV mount URL
|
||||
- Finder mounts the export
|
||||
|
||||
It can later grow into:
|
||||
|
||||
- a small desktop helper
|
||||
- a small helper app
|
||||
- one-click mount flows
|
||||
- auto-mount at login
|
||||
- status and reconnect behavior
|
||||
|
|
@ -21,52 +23,50 @@ It can later grow into:
|
|||
## What it does
|
||||
|
||||
- authenticates the user to betterNAS
|
||||
- fetches allowed mount profiles from the control plane
|
||||
- fetches allowed mount profiles from `control-server`
|
||||
- mounts approved storage exports locally
|
||||
- gives the user a native-feeling way to browse files
|
||||
|
||||
## What it should not do
|
||||
|
||||
- invent its own permissions model
|
||||
- hardcode NAS endpoints outside the control plane
|
||||
- become tightly coupled to Nextcloud
|
||||
- hardcode node endpoints outside the control-server
|
||||
- depend on the optional cloud adapter for the core mount flow
|
||||
|
||||
## Diagram
|
||||
|
||||
```text
|
||||
betterNAS system
|
||||
self-hosted betterNAS stack
|
||||
|
||||
NAS node <---------> control plane <---------> [THIS DOC] local device
|
||||
| | |
|
||||
| | |
|
||||
+---------------------------+-----------------------+-----------+
|
||||
|
|
||||
v
|
||||
cloud/web layer
|
||||
node-service <--------> control-server <--------> web control plane
|
||||
^ ^
|
||||
| |
|
||||
+------------- [THIS DOC] local device ---------+
|
||||
browser + Finder
|
||||
```
|
||||
|
||||
## Core decisions
|
||||
|
||||
- V1 can rely on native Finder WebDAV mounting.
|
||||
- A lightweight helper app is likely enough before a full custom client.
|
||||
- The local device should consume mount profiles, not raw infrastructure details.
|
||||
- V1 relies on native Finder WebDAV mounting.
|
||||
- The web UI should be enough to get the user to a mountable URL.
|
||||
- A lightweight helper app is likely enough before a full native client.
|
||||
|
||||
## User modes
|
||||
|
||||
### Mount mode
|
||||
|
||||
- user mounts a NAS export into Finder
|
||||
- user mounts a NAS export in Finder
|
||||
- files are browsed as a mounted remote disk
|
||||
|
||||
### Cloud mode
|
||||
### Browser mode
|
||||
|
||||
- user accesses the same storage through browser/mobile/cloud surfaces
|
||||
- this is not the same as a mounted filesystem
|
||||
- user manages the NAS and exports in the web control plane
|
||||
- optional later: browse files in the browser
|
||||
|
||||
## TODO
|
||||
|
||||
- Define the mount profile format the control plane returns.
|
||||
- Decide what the first local UX is: manual Finder flow, helper app, or both.
|
||||
- Define credential storage and Keychain behavior.
|
||||
- Define auto-mount, reconnect, and offline expectations.
|
||||
- Define how the local device hands off to the cloud/web layer when mount mode is not enough.
|
||||
- Define the mount profile format returned by `control-server`.
|
||||
- Decide whether the first UX is manual Finder flow, helper app, or both.
|
||||
- Define credential handling and Keychain behavior.
|
||||
- Define reconnect and auto-mount expectations.
|
||||
- Define what later native client work is actually worth doing.
|
||||
|
|
|
|||
|
|
@ -1,69 +1,71 @@
|
|||
# betterNAS Part 4: Cloud / Web Layer
|
||||
# betterNAS Part 4: Web Control Plane and Optional Cloud Layer
|
||||
|
||||
This document describes the optional browser, mobile, and cloud-drive style access layer.
|
||||
This document describes the browser UI that users interact with, plus the
|
||||
optional cloud adapter layer that may exist later.
|
||||
|
||||
## What it is
|
||||
|
||||
The cloud/web layer is the part of betterNAS that makes storage accessible beyond local mounts.
|
||||
The web control plane is part of the core product.
|
||||
|
||||
This is where we can reuse Nextcloud heavily for:
|
||||
It should provide:
|
||||
|
||||
- browser file UI
|
||||
- uploads and downloads
|
||||
- sharing links
|
||||
- WebDAV-based cloud access
|
||||
- mobile reference behavior
|
||||
- onboarding
|
||||
- node and export management
|
||||
- mount instructions
|
||||
- sharing and browser file access later
|
||||
|
||||
An optional cloud adapter may later provide:
|
||||
|
||||
- Nextcloud-backed browser file UI
|
||||
- mobile-friendly access
|
||||
- share and link workflows
|
||||
|
||||
## What it does
|
||||
|
||||
- gives users a browser-based file experience
|
||||
- supports sharing and link-based access
|
||||
- gives us a cloud mode in addition to mount mode
|
||||
- can act as a reference surface while the main betterNAS product grows
|
||||
- gives users a browser-based entry point into betterNAS
|
||||
- talks only to `control-server`
|
||||
- exposes the mount flow cleanly
|
||||
- optionally layers on cloud/mobile/share behavior later
|
||||
|
||||
## What it should not do
|
||||
|
||||
- own the product system of record
|
||||
- become the only way users access storage
|
||||
- swallow control-plane logic that should stay in betterNAS
|
||||
- own product state separately from `control-server`
|
||||
- become the only way users access their storage
|
||||
- make the optional cloud adapter part of the core mount path
|
||||
|
||||
## Diagram
|
||||
|
||||
```text
|
||||
betterNAS system
|
||||
self-hosted betterNAS stack
|
||||
|
||||
NAS node <---------> control plane <---------> local device
|
||||
| | |
|
||||
| | |
|
||||
+---------------------------+-----------------------+-----------+
|
||||
|
|
||||
v
|
||||
+----------------------+
|
||||
| [THIS DOC] cloud/web |
|
||||
|----------------------|
|
||||
| Nextcloud adapter |
|
||||
| browser UI |
|
||||
| sharing / mobile |
|
||||
+----------------------+
|
||||
node-service <--------> control-server <--------> [THIS DOC] web control plane
|
||||
^ |
|
||||
| |
|
||||
+----------- Finder mount flow -+
|
||||
|
||||
optional later:
|
||||
Nextcloud adapter / cloud/mobile/share surface
|
||||
```
|
||||
|
||||
## Core decisions
|
||||
|
||||
- The cloud/web layer is optional but very high leverage.
|
||||
- Nextcloud is a strong fit here because it already gives us file UI and sharing primitives.
|
||||
- It should sit beside mount mode, not replace it.
|
||||
- The web control plane is part of the core product now.
|
||||
- Nextcloud is optional and secondary.
|
||||
- The first user value is managing exports and getting a mount URL, not a full
|
||||
browser file manager.
|
||||
|
||||
## Likely role of Nextcloud
|
||||
## Likely near-term role of the web control plane
|
||||
|
||||
- browser-based file UI
|
||||
- share and link management
|
||||
- optional mobile and cloud-drive style access
|
||||
- adapter over the same storage exports the control plane knows about
|
||||
- sign in
|
||||
- see available NAS nodes
|
||||
- see available exports
|
||||
- request mount instructions
|
||||
- copy or launch the WebDAV mount flow
|
||||
|
||||
## TODO
|
||||
|
||||
- Decide whether Nextcloud is directly user-facing in v1 or mostly an adapter behind betterNAS.
|
||||
- Define how storage exports from the NAS node appear in the cloud/web layer.
|
||||
- Define how shares in this layer map back to control-plane access grants.
|
||||
- Define what mobile access looks like in v1.
|
||||
- Define branding and how much of the cloud/web layer stays stock vs customized.
|
||||
- Define the first user-facing screens for nodes, exports, and mount actions.
|
||||
- Define how auth/session works in the web UI.
|
||||
- Decide whether browser file viewing is part of V1 or follows later.
|
||||
- Decide whether Nextcloud remains an internal adapter or becomes user-facing.
|
||||
- Define what sharing means before adding any cloud/mobile layer.
|
||||
|
|
|
|||
|
|
@ -12,240 +12,151 @@ It answers four questions:
|
|||
## The full system
|
||||
|
||||
```text
|
||||
betterNAS build plan
|
||||
self-hosted betterNAS
|
||||
|
||||
[2] control plane
|
||||
+--------------------------------+
|
||||
| API + policy + registry + UI |
|
||||
+--------+---------------+-------+
|
||||
| |
|
||||
control/API | | cloud adapter
|
||||
v v
|
||||
[1] NAS node [4] cloud/web layer
|
||||
+------------------+ +-------------------+
|
||||
| WebDAV + agent | | Nextcloud adapter |
|
||||
| real storage | | browser/mobile |
|
||||
+---------+--------+ +---------+---------+
|
||||
| ^
|
||||
| mount profile |
|
||||
v |
|
||||
[3] local device ---------------+
|
||||
+----------------------+
|
||||
| Finder mount/helper |
|
||||
| native user entry |
|
||||
+----------------------+
|
||||
[3] web control plane
|
||||
+--------------------------------+
|
||||
| onboarding / management / UX |
|
||||
+---------------+----------------+
|
||||
|
|
||||
v
|
||||
[2] control-server
|
||||
+--------------------------------+
|
||||
| auth / nodes / exports |
|
||||
| grants / mount profiles |
|
||||
+---------------+----------------+
|
||||
|
|
||||
v
|
||||
[1] node-service
|
||||
+--------------------------------+
|
||||
| WebDAV + export runtime |
|
||||
| real storage |
|
||||
+---------------+----------------+
|
||||
^
|
||||
|
|
||||
[4] local device
|
||||
+--------------------------------+
|
||||
| browser + Finder mount |
|
||||
+--------------------------------+
|
||||
|
||||
optional later:
|
||||
- Nextcloud adapter
|
||||
- hosted control plane
|
||||
- hosted web UI
|
||||
```
|
||||
|
||||
## The core rule
|
||||
|
||||
The control plane owns product semantics.
|
||||
`control-server` owns product semantics.
|
||||
|
||||
The other three parts are execution surfaces:
|
||||
|
||||
- the NAS node serves storage
|
||||
- the local device mounts and uses storage
|
||||
- the cloud/web layer exposes storage through browser and mobile-friendly flows
|
||||
- `node-service` serves storage
|
||||
- `web control plane` exposes management and mount UX
|
||||
- `local device` consumes the issued mount flow
|
||||
|
||||
## What we steal vs write
|
||||
|
||||
| Part | Steal first | Write ourselves |
|
||||
| --------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| NAS node | NixOS/Nix module patterns, existing WebDAV servers | node agent, export model, node registration flow |
|
||||
| Control plane | Go stdlib routing, pgx/sqlc, go-redis/asynq, OpenAPI codegen | product domain model, policy engine, mount/cloud APIs, registry |
|
||||
| Local device | Finder WebDAV mount, macOS Keychain, later maybe launch agent patterns | helper app, mount profile handling, auto-mount UX |
|
||||
| Cloud/web layer | Nextcloud server, Nextcloud shell app, Nextcloud share/file UI, Nextcloud mobile references | betterNAS integration layer, mapping between product model and Nextcloud, later branded UI |
|
||||
| Part | Steal first | Write ourselves |
|
||||
| ----------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| node-service | Go WebDAV primitives, Docker packaging, later Nix module patterns | node runtime, export model, node enrollment |
|
||||
| control-server | Go stdlib routing, pgx/sqlc, Redis helpers, OpenAPI codegen | product domain model, policy engine, mount APIs, registry |
|
||||
| web control plane | Next.js app conventions, shared UI primitives | product UI, onboarding, node/export flows, mount UX |
|
||||
| local device | Finder WebDAV mount flow, macOS Keychain later | helper app or mount launcher later |
|
||||
| optional adapter | Nextcloud server and app template | betterNAS mapping layer if we decide to keep a cloud/mobile surface |
|
||||
|
||||
## Where each part should start
|
||||
|
||||
## 1. NAS node
|
||||
## 1. node-service
|
||||
|
||||
Start from:
|
||||
|
||||
- Nix flake / module
|
||||
- a standard WebDAV server
|
||||
- a very small agent process
|
||||
- one Go binary
|
||||
- one export root
|
||||
- one WebDAV surface
|
||||
- one deployable self-hosted runtime
|
||||
|
||||
Do not start by writing:
|
||||
|
||||
- custom storage protocol
|
||||
- custom file server
|
||||
- custom sync engine
|
||||
- a custom storage protocol
|
||||
- a custom sync engine
|
||||
- a complex relay stack
|
||||
|
||||
The NAS node should be boring and reproducible.
|
||||
|
||||
## 2. Control plane
|
||||
## 2. control-server
|
||||
|
||||
Start from:
|
||||
|
||||
- Go
|
||||
- standard library routing first
|
||||
- Postgres via `pgx` and `sqlc`
|
||||
- Redis via `go-redis`
|
||||
- OpenAPI-driven contracts
|
||||
- standalone API mindset
|
||||
- one API
|
||||
- one durable data model
|
||||
- node registration and mount profile issuance
|
||||
|
||||
Do not start by writing:
|
||||
|
||||
- microservices
|
||||
- custom file transport
|
||||
- a proxy that sits in the middle of every file transfer
|
||||
- file proxying by default
|
||||
- hosted-only assumptions
|
||||
|
||||
This is the first real thing we should build.
|
||||
|
||||
## 3. Local device
|
||||
## 3. web control plane
|
||||
|
||||
Start from:
|
||||
|
||||
- native Finder `Connect to Server`
|
||||
- WebDAV mount URLs issued by the control plane
|
||||
- sign in
|
||||
- list nodes and exports
|
||||
- show mount URL and mount instructions
|
||||
|
||||
Do not start by writing:
|
||||
|
||||
- a large browser file manager
|
||||
- a second backend hidden inside Next.js
|
||||
|
||||
## 4. local device
|
||||
|
||||
Start from:
|
||||
|
||||
- Finder `Connect to Server`
|
||||
- WebDAV mount URL issued by `control-server`
|
||||
|
||||
Then later add:
|
||||
|
||||
- a lightweight helper app
|
||||
- one-click helper
|
||||
- Keychain integration
|
||||
- auto-mount at login
|
||||
|
||||
Do not start by writing:
|
||||
|
||||
- a full custom desktop sync client
|
||||
- a Finder extension
|
||||
- a new filesystem driver
|
||||
|
||||
## 4. Cloud / web layer
|
||||
|
||||
Start from:
|
||||
|
||||
- stock Nextcloud
|
||||
- current shell app
|
||||
- Nextcloud browser/share/mobile primitives
|
||||
|
||||
Then later add:
|
||||
|
||||
- betterNAS-specific integration pages
|
||||
- standalone control-plane web UI
|
||||
- custom branding or replacement UI where justified
|
||||
|
||||
Do not start by writing:
|
||||
|
||||
- a full custom browser file manager
|
||||
- a custom mobile client
|
||||
- a custom sharing stack
|
||||
|
||||
## Recommended build order
|
||||
|
||||
### Phase A: make the storage path real
|
||||
### Phase A: make the self-hosted mount path real
|
||||
|
||||
1. NAS node can expose a directory over WebDAV
|
||||
2. control plane can register the node and its exports
|
||||
3. local device can mount that export in Finder
|
||||
1. node-service exposes a directory over WebDAV
|
||||
2. control-server registers the node and its exports
|
||||
3. web control plane shows the export and mount action
|
||||
4. local device mounts the export in Finder
|
||||
|
||||
This is the shortest path to a real product loop.
|
||||
### Phase B: make the product real
|
||||
|
||||
### Phase B: make the product model real
|
||||
1. add durable users, nodes, exports, grants, mount profiles
|
||||
2. add auth and token lifecycle
|
||||
3. add a proper web UI for admin and user control flows
|
||||
|
||||
1. add users, devices, NAS nodes, exports, grants, mount profiles
|
||||
2. add auth and policy
|
||||
3. add a simple standalone web UI for admin/control use
|
||||
### Phase C: make deployment real
|
||||
|
||||
This is where betterNAS becomes its own product.
|
||||
1. define Docker self-hosting shape
|
||||
2. define Nix-based NAS host install shape
|
||||
3. define remote access story for non-local usage
|
||||
|
||||
### Phase C: add cloud mode
|
||||
### Phase D: add optional adapter surfaces
|
||||
|
||||
1. connect the same storage into Nextcloud
|
||||
2. expose browser/mobile/share flows
|
||||
3. map Nextcloud behavior back to betterNAS product semantics
|
||||
|
||||
This is high leverage, but should not block Phase A.
|
||||
|
||||
## External parts we should deliberately reuse
|
||||
|
||||
### NAS node
|
||||
|
||||
- WebDAV server implementation
|
||||
- Nix module patterns
|
||||
|
||||
### Control plane
|
||||
|
||||
- Go API service scaffold
|
||||
- Postgres
|
||||
- Redis
|
||||
|
||||
### Local device
|
||||
|
||||
- Finder's native WebDAV mounting
|
||||
- macOS credential storage
|
||||
|
||||
### Cloud/web layer
|
||||
|
||||
- Nextcloud server
|
||||
- Nextcloud app shell
|
||||
- Nextcloud share/browser behavior
|
||||
- Nextcloud mobile and desktop references
|
||||
|
||||
## From-scratch parts we should deliberately own
|
||||
|
||||
### NAS node
|
||||
|
||||
- node enrollment
|
||||
- export registration
|
||||
- machine identity and health reporting
|
||||
|
||||
### Control plane
|
||||
|
||||
- full backend domain model
|
||||
- access and policy model
|
||||
- mount profile generation
|
||||
- cloud profile generation
|
||||
- audit and registry
|
||||
|
||||
### Local device
|
||||
|
||||
- user-friendly mounting workflow
|
||||
- helper app if needed
|
||||
- local mount orchestration
|
||||
|
||||
### Cloud/web layer
|
||||
|
||||
- betterNAS-to-Nextcloud mapping layer
|
||||
- standalone betterNAS product UI over time
|
||||
|
||||
## First scaffolds to use
|
||||
|
||||
| Part | First scaffold |
|
||||
| --------------- | ------------------------------------------------------------- |
|
||||
| NAS node | Nix flake/module + WebDAV server service config |
|
||||
| Control plane | Go service + OpenAPI contract + Postgres/Redis adapters later |
|
||||
| Local device | documented Finder mount flow, then lightweight helper app |
|
||||
| Cloud/web layer | current Nextcloud scaffold and shell app |
|
||||
|
||||
## What not to overbuild early
|
||||
|
||||
- custom sync engine
|
||||
- custom desktop client
|
||||
- custom mobile app
|
||||
- many backend services
|
||||
- control-plane-in-the-data-path file proxy
|
||||
|
||||
Those can come later if the simpler stack proves insufficient.
|
||||
1. add Nextcloud only if browser/share/mobile value justifies it
|
||||
2. keep it out of the critical mount path
|
||||
|
||||
## Build goal for V1
|
||||
|
||||
V1 should prove one clean loop:
|
||||
|
||||
```text
|
||||
user picks NAS export in betterNAS UI
|
||||
-> control plane issues mount profile
|
||||
-> local device mounts WebDAV export
|
||||
-> user sees and uses files in Finder
|
||||
-> optional Nextcloud surface exposes the same storage in cloud mode
|
||||
user opens betterNAS web UI
|
||||
-> sees a registered export
|
||||
-> requests mount instructions
|
||||
-> Finder mounts the WebDAV export
|
||||
-> user sees and uses files from the NAS
|
||||
```
|
||||
|
||||
If that loop works, the architecture is sound.
|
||||
|
||||
## TODO
|
||||
|
||||
- Choose the exact WebDAV server for the NAS node.
|
||||
- Decide the first Nix module layout for node installation.
|
||||
- Define the first database-backed control-plane entities.
|
||||
- Decide whether the local device starts as documentation-only or a helper app.
|
||||
- Decide when the Nextcloud cloud/web layer becomes user-facing in v1.
|
||||
|
|
|
|||
|
|
@ -3,61 +3,76 @@
|
|||
This file is the canonical contract for the repository.
|
||||
|
||||
If the planning docs, scaffold code, or future tasks disagree, this file and
|
||||
[`packages/contracts`](../packages/contracts)
|
||||
win.
|
||||
[`packages/contracts`](../packages/contracts) win.
|
||||
|
||||
## The single first task
|
||||
## Product default
|
||||
|
||||
Before splitting work across agents, do one foundation task:
|
||||
betterNAS is self-hosted first.
|
||||
|
||||
- scaffold the four product parts
|
||||
- lock the shared contracts
|
||||
- define one end-to-end verification loop
|
||||
- enforce clear ownership boundaries
|
||||
For the current product shape, the user should be able to run the whole stack on
|
||||
their NAS machine:
|
||||
|
||||
That first task should leave the repo in a state where later work can be
|
||||
parallelized without interface drift.
|
||||
- `node-service` serves the real files over WebDAV
|
||||
- `control-server` owns auth, nodes, exports, grants, and mount profiles
|
||||
- `web control plane` is the browser UI over the control-server
|
||||
- the local device mounts an issued WebDAV URL in Finder
|
||||
|
||||
## The four parts
|
||||
Optional hosted deployments can come later. Optional Nextcloud integration can
|
||||
come later.
|
||||
|
||||
## The core system
|
||||
|
||||
```text
|
||||
betterNAS canonical contract
|
||||
betterNAS canonical contract
|
||||
|
||||
[2] control plane
|
||||
+-----------------------------------+
|
||||
| system of record |
|
||||
| users / devices / nodes / grants |
|
||||
| mount profiles / cloud profiles |
|
||||
+---------+---------------+---------+
|
||||
| |
|
||||
control/API | | cloud adapter
|
||||
v v
|
||||
[1] NAS node [4] cloud / web layer
|
||||
+-------------------+ +----------------------+
|
||||
| WebDAV + node | | Nextcloud adapter |
|
||||
| real file bytes | | browser / mobile |
|
||||
+---------+---------+ +----------+-----------+
|
||||
| ^
|
||||
| mount profile |
|
||||
v |
|
||||
[3] local device --------------+
|
||||
+----------------------+
|
||||
| Finder mount/helper |
|
||||
| native user entry |
|
||||
+----------------------+
|
||||
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
|
||||
|
||||
1. The control plane is the system of record.
|
||||
2. File bytes should flow as directly as possible between the NAS node and the
|
||||
local device.
|
||||
3. The control plane should issue policy, grants, and profiles. It should not
|
||||
become the default file proxy.
|
||||
4. The NAS node should serve WebDAV directly whenever possible.
|
||||
5. The local device consumes mount profiles. It does not hardcode infra details.
|
||||
6. The cloud/web layer is optional and secondary. Nextcloud is an adapter, not
|
||||
the product center.
|
||||
1. `control-server` is the system of record.
|
||||
2. `node-service` serves the bytes.
|
||||
3. `web control plane` is a UI over `control-server`, not a second policy
|
||||
backend.
|
||||
4. The main data path should be `local device <-> node-service` whenever
|
||||
possible.
|
||||
5. `control-server` should issue access, grants, and mount profiles. It should
|
||||
not become the default file proxy.
|
||||
6. The self-hosted stack should work without Nextcloud.
|
||||
7. Nextcloud, if used, is an optional adapter and secondary surface.
|
||||
|
||||
## Canonical sources of truth
|
||||
|
||||
|
|
@ -67,7 +82,7 @@ Use these in this order:
|
|||
for boundaries, ownership, and delivery rules
|
||||
2. [`packages/contracts`](../packages/contracts)
|
||||
for machine-readable types, schemas, and route constants
|
||||
3. the part docs for local detail:
|
||||
3. the part docs:
|
||||
- [`docs/01-nas-node.md`](./01-nas-node.md)
|
||||
- [`docs/02-control-plane.md`](./02-control-plane.md)
|
||||
- [`docs/03-local-device.md`](./03-local-device.md)
|
||||
|
|
@ -84,31 +99,33 @@ The monorepo is split into these primary implementation lanes:
|
|||
- [`apps/nextcloud-app`](../apps/nextcloud-app)
|
||||
- [`packages/contracts`](../packages/contracts)
|
||||
|
||||
Every parallel task should primarily stay inside one of those lanes unless it is
|
||||
an explicit contract task.
|
||||
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 that let all four
|
||||
parts exist at once.
|
||||
The first shared contract set should cover only the seams needed for the
|
||||
self-hosted mount flow.
|
||||
|
||||
### NAS node -> control plane
|
||||
### Node-service -> control-server
|
||||
|
||||
- node registration
|
||||
- node heartbeat
|
||||
- export inventory
|
||||
|
||||
### Local device -> control plane
|
||||
### Web control plane -> control-server
|
||||
|
||||
- list allowed exports
|
||||
- auth/session bootstrapping
|
||||
- list nodes and exports
|
||||
- issue mount profile
|
||||
- issue share or cloud profile later
|
||||
|
||||
### Cloud/web layer -> control plane
|
||||
### Local device -> control-server
|
||||
|
||||
- issue cloud profile
|
||||
- read export metadata
|
||||
- fetch mount instructions
|
||||
- receive issued WebDAV URL and credentials or token material
|
||||
|
||||
### Control plane internal
|
||||
### Control-server internal
|
||||
|
||||
- health
|
||||
- version
|
||||
|
|
@ -117,57 +134,61 @@ parts exist at once.
|
|||
- `StorageExport`
|
||||
- `AccessGrant`
|
||||
- `MountProfile`
|
||||
- `CloudProfile`
|
||||
- `AuditEvent`
|
||||
|
||||
## Parallel work boundaries
|
||||
|
||||
Each area gets an owner and a narrow write surface.
|
||||
| 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 |
|
||||
|
||||
| Part | Owns | May read | Must not own |
|
||||
| --------------- | ------------------------------------------------ | ----------------------------- | ------------------------------ |
|
||||
| NAS node | node runtime, export reporting, WebDAV config | contracts, control-plane docs | product policy |
|
||||
| Control plane | domain model, grants, profile issuance, registry | everything | direct file serving by default |
|
||||
| Local device | mount UX, helper flows, credential handling | contracts, control-plane docs | access policy |
|
||||
| Cloud/web layer | Nextcloud adapter, browser/mobile integration | contracts, control-plane docs | source of truth |
|
||||
|
||||
The only shared write surface across teams should be:
|
||||
The shared write surface across parts should stay narrow:
|
||||
|
||||
- [`packages/contracts`](../packages/contracts)
|
||||
- this file when the architecture contract changes
|
||||
- this file when architecture changes
|
||||
|
||||
## Verification loop
|
||||
|
||||
This is the first loop every scaffold and agent should target.
|
||||
This is the main loop every near-term task should support.
|
||||
|
||||
```text
|
||||
[1] mock or real NAS node exposes a WebDAV export
|
||||
-> [2] control plane registers the node and export
|
||||
-> [3] local device asks for a mount profile
|
||||
-> [3] local device receives a WebDAV mount URL
|
||||
-> user can mount the export in Finder
|
||||
-> [4] optional cloud/web layer can expose the same export in cloud mode
|
||||
[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 help one of those steps become real, it is probably too
|
||||
early.
|
||||
If a task does not make one of those steps more real, it is probably too early.
|
||||
|
||||
## Definition of done for the foundation scaffold
|
||||
## Definition of done for the current foundation
|
||||
|
||||
The initial scaffold is complete when:
|
||||
The current foundation is in good shape when:
|
||||
|
||||
- all four parts have a documented entry point
|
||||
- the control plane can represent nodes, exports, grants, and profiles
|
||||
- the contracts package exports the first shared shapes and schemas
|
||||
- local verification can prove the mount-profile loop end to end
|
||||
- future agents can work inside one part without inventing new interfaces
|
||||
- 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
|
||||
|
||||
1. No part may invent private request or response shapes for shared flows.
|
||||
2. Contract changes must update
|
||||
[`packages/contracts`](../packages/contracts)
|
||||
2. Contract changes must update [`packages/contracts`](../packages/contracts)
|
||||
first.
|
||||
3. Architecture changes must update this file in the same change.
|
||||
4. Additive contract changes are preferred over breaking ones.
|
||||
5. New tasks should target one part at a time unless they are explicitly
|
||||
contract tasks.
|
||||
5. Prioritize the self-hosted mount loop before optional cloud/mobile work.
|
||||
|
|
|
|||
|
|
@ -1,46 +1,55 @@
|
|||
# betterNAS References
|
||||
|
||||
This file tracks the upstream repos, tools, and docs we are likely to reuse, reference, fork from, or borrow ideas from as betterNAS evolves.
|
||||
This file tracks the upstream repos, tools, and docs we are likely to reuse,
|
||||
reference, fork from, or borrow ideas from as betterNAS evolves.
|
||||
|
||||
The goal is simple: do not lose the external pieces that give us leverage.
|
||||
The ordering matters:
|
||||
|
||||
## NAS node
|
||||
1. self-hosted WebDAV stack first
|
||||
2. control-server and web control plane second
|
||||
3. optional cloud adapter later
|
||||
|
||||
### WebDAV server candidates
|
||||
## Primary now: self-hosted DAV stack
|
||||
|
||||
- `rclone serve webdav`
|
||||
- repo: https://github.com/rclone/rclone
|
||||
- why: fast way to stand up a WebDAV layer over existing storage
|
||||
### Node-service and WebDAV
|
||||
|
||||
- Go WebDAV package
|
||||
- docs: https://pkg.go.dev/golang.org/x/net/webdav
|
||||
- why: embeddable WebDAV implementation for the NAS runtime
|
||||
|
||||
- `hacdias/webdav`
|
||||
- repo: https://github.com/hacdias/webdav
|
||||
- why: small standalone WebDAV server, easy to reason about
|
||||
- why: small standalone WebDAV reference
|
||||
|
||||
- Apache `mod_dav`
|
||||
- docs: https://httpd.apache.org/docs/current/mod/mod_dav.html
|
||||
- why: standard WebDAV implementation if we want conventional infra
|
||||
- `rclone serve webdav`
|
||||
- repo: https://github.com/rclone/rclone
|
||||
- why: useful reference for standing up WebDAV over existing storage
|
||||
|
||||
### Nix / host configuration
|
||||
### Self-hosting and NAS configuration
|
||||
|
||||
- NixOS manual
|
||||
- docs: https://nixos.org/manual/nixos/stable/
|
||||
- why: host module design, service config, declarative machine setup
|
||||
- why: host module design and declarative machine setup
|
||||
|
||||
- Nixpkgs
|
||||
- repo: https://github.com/NixOS/nixpkgs
|
||||
- why: reference for packaging and service modules
|
||||
- why: service module and packaging reference
|
||||
|
||||
## Control plane
|
||||
- Docker Compose docs
|
||||
- docs: https://docs.docker.com/compose/
|
||||
- why: current self-hosted runtime packaging baseline
|
||||
|
||||
## Primary now: control-server
|
||||
|
||||
### Backend and infra references
|
||||
|
||||
- Go routing enhancements
|
||||
- docs: https://go.dev/blog/routing-enhancements
|
||||
- why: best low-dependency baseline if we stay with the standard library
|
||||
- why: low-dependency baseline for the API
|
||||
|
||||
- `chi`
|
||||
- repo: https://github.com/go-chi/chi
|
||||
- why: thin stdlib-friendly router if we want middleware and route groups
|
||||
- why: thin router if stdlib becomes too bare
|
||||
|
||||
- PostgreSQL
|
||||
- docs: https://www.postgresql.org/docs/
|
||||
|
|
@ -48,7 +57,7 @@ The goal is simple: do not lose the external pieces that give us leverage.
|
|||
|
||||
- `pgx`
|
||||
- repo: https://github.com/jackc/pgx
|
||||
- why: Postgres-first Go driver and toolkit
|
||||
- why: Postgres-first Go driver
|
||||
|
||||
- `sqlc`
|
||||
- repo: https://github.com/sqlc-dev/sqlc
|
||||
|
|
@ -56,96 +65,70 @@ The goal is simple: do not lose the external pieces that give us leverage.
|
|||
|
||||
- Redis
|
||||
- docs: https://redis.io/docs/latest/
|
||||
- why: cache, jobs, ephemeral coordination
|
||||
- why: cache, jobs, and ephemeral coordination
|
||||
|
||||
- `go-redis`
|
||||
- repo: https://github.com/redis/go-redis
|
||||
- why: primary Redis client for Go
|
||||
- why: primary Redis client
|
||||
|
||||
- `asynq`
|
||||
- repo: https://github.com/hibiken/asynq
|
||||
- why: practical Redis-backed background jobs
|
||||
|
||||
- `koanf`
|
||||
- repo: https://github.com/knadh/koanf
|
||||
- why: layered config if the control plane grows beyond env-only config
|
||||
|
||||
- `envconfig`
|
||||
- repo: https://github.com/kelseyhightower/envconfig
|
||||
- why: small env-only config loader
|
||||
|
||||
- `log/slog`
|
||||
- docs: https://pkg.go.dev/log/slog
|
||||
- why: structured logging without extra dependencies
|
||||
|
||||
- `oapi-codegen`
|
||||
- repo: https://github.com/oapi-codegen/oapi-codegen
|
||||
- why: generate Go and TS surfaces from OpenAPI with less drift
|
||||
|
||||
### SSH access / gateway reference
|
||||
## Primary now: web control plane and local device
|
||||
|
||||
- `sshpiper`
|
||||
- repo: https://github.com/tg123/sshpiper
|
||||
- why: SSH proxy/gateway reference if we add SSH-brokered access later
|
||||
### Web control plane
|
||||
|
||||
## Local device
|
||||
- Next.js
|
||||
- repo: https://github.com/vercel/next.js
|
||||
- why: control-plane web UI
|
||||
|
||||
### macOS native mount references
|
||||
- Turborepo
|
||||
- docs: https://turborepo.dev/repo/docs/crafting-your-repository/structuring-a-repository
|
||||
- why: monorepo boundaries and task graph rules
|
||||
|
||||
### macOS mount UX
|
||||
|
||||
- Apple Finder `Connect to Server`
|
||||
- docs: https://support.apple.com/en-lamr/guide/mac-help/mchlp3015/mac
|
||||
- why: baseline native mounting UX on macOS
|
||||
- why: baseline native mount UX on macOS
|
||||
|
||||
- Apple Finder WebDAV mounting
|
||||
- docs: https://support.apple.com/is-is/guide/mac-help/mchlp1546/mac
|
||||
- why: direct WebDAV mount behavior in Finder
|
||||
|
||||
### macOS integration references
|
||||
|
||||
- Apple developer docs
|
||||
- docs: https://developer.apple.com/documentation/
|
||||
- why: Keychain, launch agents, desktop helpers, future native integration
|
||||
- why: Keychain, helper apps, launch agents, and later native integration
|
||||
|
||||
- Keychain data protection
|
||||
- docs: https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web
|
||||
- why: baseline secret-storage model for device credentials
|
||||
|
||||
- Finder Sync extensions
|
||||
- docs: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/Finder.html
|
||||
- why: future helper-app integration pattern if Finder UX grows
|
||||
|
||||
- WebDAV RFC 4918
|
||||
- docs: https://www.rfc-editor.org/rfc/rfc4918
|
||||
- why: protocol semantics and caveats
|
||||
|
||||
## Cloud / web layer
|
||||
## Optional later: cloud adapter
|
||||
|
||||
### Nextcloud server and app references
|
||||
|
||||
- Nextcloud server
|
||||
- repo: https://github.com/nextcloud/server
|
||||
- why: cloud/web/share substrate
|
||||
- why: optional browser/share/mobile substrate
|
||||
|
||||
- Nextcloud app template
|
||||
- repo: https://github.com/nextcloud/app_template
|
||||
- why: official starting point for the thin shell app
|
||||
- why: official starting point for the thin adapter app
|
||||
|
||||
- Nextcloud AppAPI / ExApps
|
||||
- docs: https://docs.nextcloud.com/server/latest/admin_manual/exapps_management/AppAPIAndExternalApps.html
|
||||
- why: external app integration model
|
||||
|
||||
### Nextcloud client references
|
||||
|
||||
- Nextcloud desktop
|
||||
- repo: https://github.com/nextcloud/desktop
|
||||
- why: Finder/cloud-drive style reference behavior
|
||||
|
||||
- Nextcloud iOS
|
||||
- repo: https://github.com/nextcloud/ios
|
||||
- why: mobile reference implementation
|
||||
|
||||
### Nextcloud storage and protocol references
|
||||
|
||||
- Nextcloud WebDAV access
|
||||
- docs: https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html
|
||||
- why: protocol and client behavior reference
|
||||
|
|
@ -154,20 +137,10 @@ The goal is simple: do not lose the external pieces that give us leverage.
|
|||
- docs: https://docs.nextcloud.com/server/latest/user_manual/en/external_storage/external_storage.html
|
||||
- why: storage aggregation reference
|
||||
|
||||
- Nextcloud theming / branded clients
|
||||
- docs: https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/theming.html
|
||||
- why: future branding path if Nextcloud stays user-facing
|
||||
|
||||
## Frontend
|
||||
|
||||
- Next.js
|
||||
- repo: https://github.com/vercel/next.js
|
||||
- why: likely standalone control-plane web UI
|
||||
|
||||
## Working rule
|
||||
|
||||
Use these references in this order:
|
||||
|
||||
1. steal primitives that already solve boring problems
|
||||
2. adapt them at the control-plane boundary
|
||||
3. only fork or replace when the product meaningfully diverges
|
||||
1. steal primitives that solve the self-hosted DAV problem first
|
||||
2. adapt them at the control-server boundary
|
||||
3. only pull in optional cloud layers when the core mount product is solid
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue