mirror of
https://github.com/harivansh-afk/betterNAS.git
synced 2026-04-15 07:04:44 +00:00
update docs
This commit is contained in:
parent
c5be520772
commit
5bc24fa99d
11 changed files with 591 additions and 632 deletions
110
README.md
110
README.md
|
|
@ -1,41 +1,83 @@
|
||||||
# betterNAS
|
# betterNAS
|
||||||
|
|
||||||
- control-plane owns policy and identity (decides)
|
betterNAS is a self-hostable WebDAV stack for mounting NAS exports in Finder.
|
||||||
- node-agent owns file serving (serves)
|
|
||||||
- web owns UX (consumer facing)
|
|
||||||
- nextcloud-app is optional adapter only for cloud storage in s3 n shit
|
|
||||||
|
|
||||||
## Monorepo
|
The default product shape is:
|
||||||
|
|
||||||
- `apps/web`: Next.js control-plane UI
|
- `node-service` serves the real files from the NAS over WebDAV
|
||||||
- `apps/control-plane`: Go control-plane service
|
- `control-server` owns auth, nodes, exports, grants, and mount profile issuance
|
||||||
- `apps/node-agent`: Go NAS runtime / WebDAV node
|
- `web control plane` lets the user manage the NAS and get mount instructions
|
||||||
- `apps/nextcloud-app`: optional Nextcloud adapter
|
- `macOS client` starts as native Finder WebDAV mounting, with a thin helper later
|
||||||
- `packages/contracts`: canonical shared contracts
|
|
||||||
- `packages/ui`: shared React UI
|
|
||||||
- `infra/docker`: local Docker runtime
|
|
||||||
|
|
||||||
The root planning and delegation guide lives in [skeleton.md](./skeleton.md).
|
For now, the whole stack should be able to run on the user's NAS device.
|
||||||
|
|
||||||
|
## Current repo shape
|
||||||
|
|
||||||
|
- `apps/node-agent`
|
||||||
|
- NAS-side Go runtime and WebDAV server
|
||||||
|
- `apps/control-plane`
|
||||||
|
- Go backend for auth, registry, and mount profile issuance
|
||||||
|
- `apps/web`
|
||||||
|
- Next.js web control plane
|
||||||
|
- `apps/nextcloud-app`
|
||||||
|
- optional Nextcloud adapter, not the product center
|
||||||
|
- `packages/contracts`
|
||||||
|
- canonical shared contracts
|
||||||
|
- `infra/docker`
|
||||||
|
- self-hosted local stack
|
||||||
|
|
||||||
|
The main planning docs are:
|
||||||
|
|
||||||
|
- [docs/architecture.md](./docs/architecture.md)
|
||||||
|
- [skeleton.md](./skeleton.md)
|
||||||
|
- [docs/05-build-plan.md](./docs/05-build-plan.md)
|
||||||
|
|
||||||
|
## Default runtime model
|
||||||
|
|
||||||
|
```text
|
||||||
|
self-hosted betterNAS on the user's NAS
|
||||||
|
|
||||||
|
+------------------------------+
|
||||||
|
| web control plane |
|
||||||
|
| Next.js UI |
|
||||||
|
+--------------+---------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+------------------------------+
|
||||||
|
| control-server |
|
||||||
|
| auth / nodes / exports |
|
||||||
|
| grants / mount profiles |
|
||||||
|
+--------------+---------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+------------------------------+
|
||||||
|
| node-service |
|
||||||
|
| WebDAV + export runtime |
|
||||||
|
| real NAS bytes |
|
||||||
|
+------------------------------+
|
||||||
|
|
||||||
|
user Mac
|
||||||
|
|
|
||||||
|
+--> browser -> web control plane
|
||||||
|
|
|
||||||
|
+--> Finder -> WebDAV mount URL from control-server
|
||||||
|
```
|
||||||
|
|
||||||
## Verify
|
## Verify
|
||||||
|
|
||||||
Run the repo acceptance loop with:
|
Static verification:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm verify
|
pnpm verify
|
||||||
```
|
```
|
||||||
|
|
||||||
## Runtime loop
|
Bootstrap clone-local runtime settings:
|
||||||
|
|
||||||
Bootstrap clone-local runtime settings with:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm agent:bootstrap
|
pnpm agent:bootstrap
|
||||||
```
|
```
|
||||||
|
|
||||||
If `.env.agent` is missing, bootstrap writes clone-local defaults for this checkout.
|
Bring the self-hosted stack up, verify it, and tear it down:
|
||||||
|
|
||||||
Bring the stack up, verify it, and tear it down with:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm stack:up
|
pnpm stack:up
|
||||||
|
|
@ -43,16 +85,30 @@ pnpm stack:verify
|
||||||
pnpm stack:down --volumes
|
pnpm stack:down --volumes
|
||||||
```
|
```
|
||||||
|
|
||||||
## Agent loop
|
Run the full loop:
|
||||||
|
|
||||||
Run the full static and integration loop with:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm agent:verify
|
pnpm agent:verify
|
||||||
```
|
```
|
||||||
|
|
||||||
Create or refresh the sibling agent clones with:
|
## Current end-to-end slice
|
||||||
|
|
||||||
```bash
|
The first proven slice is:
|
||||||
pnpm clones:setup
|
|
||||||
```
|
1. boot the stack with `pnpm stack:up`
|
||||||
|
2. verify it with `pnpm stack:verify`
|
||||||
|
3. get the WebDAV mount URL
|
||||||
|
4. mount it in Finder
|
||||||
|
|
||||||
|
If the stack is running on a remote machine, tunnel the WebDAV port first, then
|
||||||
|
use Finder `Connect to Server` with the tunneled URL.
|
||||||
|
|
||||||
|
## Product boundary
|
||||||
|
|
||||||
|
The default betterNAS product is self-hosted and WebDAV-first.
|
||||||
|
|
||||||
|
Nextcloud remains optional and secondary:
|
||||||
|
|
||||||
|
- useful later for browser/mobile/share surfaces
|
||||||
|
- not required for the core mount flow
|
||||||
|
- not the system of record
|
||||||
|
|
|
||||||
10
TODO.md
10
TODO.md
|
|
@ -5,7 +5,11 @@
|
||||||
- [x] Add root formatting, verification, and Go formatting rails.
|
- [x] Add root formatting, verification, and Go formatting rails.
|
||||||
- [x] Add hard boundary checks so apps and packages cannot drift across lanes with private imports.
|
- [x] Add hard boundary checks so apps and packages cannot drift across lanes with private imports.
|
||||||
- [x] Make the first contract-backed mount loop real: node registration, export inventory, mount profile issuance, and a Finder-mountable WebDAV export.
|
- [x] Make the first contract-backed mount loop real: node registration, export inventory, mount profile issuance, and a Finder-mountable WebDAV export.
|
||||||
- [ ] Add a manual E2E runbook for remote-host WebDAV testing from a Mac over SSH tunnel.
|
- [x] Prove the first manual remote-host WebDAV mount from a Mac over SSH tunnel.
|
||||||
- [ ] Surface exports and issued mount URLs in the web control plane.
|
- [ ] Surface exports and issued mount URLs in the web control plane.
|
||||||
- [ ] Define the Nix/module shape for installing the node agent and export runtime on a NAS host.
|
- [ ] Add durable control-server storage for nodes, exports, grants, and mount profiles.
|
||||||
- [ ] Decide whether the node agent should self-register or stay control-plane registered by bootstrap tooling.
|
- [ ] Define the self-hosted deployment shape for the full stack on a NAS device.
|
||||||
|
- [ ] Define the Nix/module shape for installing the node-service on a NAS host.
|
||||||
|
- [ ] Decide whether the node-service should self-register or stay bootstrap-registered.
|
||||||
|
- [ ] Decide whether browser file viewing belongs in V1 web control plane or later.
|
||||||
|
- [ ] Define if and when the optional Nextcloud adapter comes back into scope.
|
||||||
|
|
|
||||||
70
control.md
70
control.md
|
|
@ -1,51 +1,51 @@
|
||||||
# Control
|
# Control
|
||||||
|
|
||||||
This clone is the main repo.
|
This repo is the coordination and implementation ground for betterNAS.
|
||||||
|
|
||||||
Use it for:
|
Use it for:
|
||||||
|
|
||||||
- shared contracts
|
- shared contracts
|
||||||
- repo guardrails
|
- architecture and planning docs
|
||||||
- runtime scripts
|
- runtime scripts
|
||||||
- integration verification
|
- stack verification
|
||||||
- architecture and coordination
|
- implementation of the self-hosted stack
|
||||||
|
|
||||||
Planned clone layout:
|
## Current product focus
|
||||||
|
|
||||||
```text
|
The default betterNAS product is:
|
||||||
/home/rathi/Documents/GitHub/betterNAS/
|
|
||||||
betterNAS
|
|
||||||
betterNAS-runtime
|
|
||||||
betterNAS-control
|
|
||||||
betterNAS-node
|
|
||||||
```
|
|
||||||
|
|
||||||
Clone roles:
|
- self-hosted on the user's NAS
|
||||||
|
- WebDAV-first
|
||||||
|
- Finder-mountable
|
||||||
|
- managed through a web control plane
|
||||||
|
|
||||||
- `betterNAS`
|
The main parts are:
|
||||||
- main coordination repo
|
|
||||||
- owns contracts, scripts, and shared verification rules
|
|
||||||
- `betterNAS-runtime`
|
|
||||||
- owns Docker Compose, stack env, readiness checks, and end-to-end runtime verification
|
|
||||||
- `betterNAS-control`
|
|
||||||
- owns the Go control plane and contract-backed API behavior
|
|
||||||
- `betterNAS-node`
|
|
||||||
- owns the node agent, WebDAV serving, and NAS-side registration/export behavior
|
|
||||||
|
|
||||||
Rules:
|
- `node-service`
|
||||||
|
- `apps/node-agent`
|
||||||
|
- `control-server`
|
||||||
|
- `apps/control-plane`
|
||||||
|
- `web control plane`
|
||||||
|
- `apps/web`
|
||||||
|
- `optional cloud adapter`
|
||||||
|
- `apps/nextcloud-app`
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
- shared interface changes land in `packages/contracts` first
|
- shared interface changes land in `packages/contracts` first
|
||||||
- runtime verification must stay green in the main repo
|
- `docs/architecture.md` is the canonical architecture contract
|
||||||
- feature agents should stay inside their assigned clone unless a contract change is required
|
- the self-hosted mount flow is the critical path
|
||||||
|
- optional Nextcloud work must not drive the main architecture
|
||||||
|
|
||||||
Agent command surface:
|
## Command surface
|
||||||
|
|
||||||
- main repo creates or refreshes sibling clones with `pnpm clones:setup`
|
- `pnpm verify`
|
||||||
- each clone bootstraps itself with `pnpm agent:bootstrap`
|
- static verification
|
||||||
- each clone runs the full loop with `pnpm agent:verify`
|
- `pnpm stack:up`
|
||||||
|
- boot the self-hosted stack
|
||||||
Agent prompts live in:
|
- `pnpm stack:verify`
|
||||||
|
- verify the working stack
|
||||||
- `docs/agents/runtime-agent.md`
|
- `pnpm stack:down --volumes`
|
||||||
- `docs/agents/control-plane-agent.md`
|
- tear the stack down cleanly
|
||||||
- `docs/agents/node-agent.md`
|
- `pnpm agent:verify`
|
||||||
|
- bootstrap, verify, boot, and stack-verify in one loop
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# betterNAS Part 1: NAS Node
|
# 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
|
## What it is
|
||||||
|
|
||||||
|
|
@ -8,10 +9,11 @@ The NAS node is the machine that actually has the storage.
|
||||||
|
|
||||||
It should run:
|
It should run:
|
||||||
|
|
||||||
- a WebDAV server
|
- the `node-service`
|
||||||
- a small betterNAS node agent
|
- a WebDAV server surface
|
||||||
- declarative config via Nix
|
- export configuration
|
||||||
- optional tunnel or relay connection if the machine is not directly reachable
|
- 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:
|
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
|
- serves the real file bytes
|
||||||
- exposes chosen directories over WebDAV
|
- exposes chosen directories over WebDAV
|
||||||
- registers itself with the control plane
|
- reports identity, health, and exports to `control-server`
|
||||||
- reports health, identity, and available exports
|
- stays simple enough to self-host on a single NAS box
|
||||||
- optionally keeps an outbound connection alive for remote access
|
|
||||||
|
|
||||||
## What it should not do
|
## What it should not do
|
||||||
|
|
||||||
- own user-facing product logic
|
- own product policy
|
||||||
- decide permissions by itself
|
- decide user access rules by itself
|
||||||
- become the system of record for shares, devices, or policies
|
- become the system of record for users, grants, or shares
|
||||||
|
|
||||||
## Diagram
|
## Diagram
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS system
|
self-hosted betterNAS stack
|
||||||
|
|
||||||
local device <-------> control plane <-------> cloud/web layer
|
web control plane ---> control-server ---> [THIS DOC] node-service
|
||||||
| | |
|
^ |
|
||||||
| | |
|
| |
|
||||||
+-------------------------+--------------------------+
|
+---------------- user browser ----------+
|
||||||
|
|
|
||||||
v
|
local Mac ---------------- Finder mount ----------+
|
||||||
+---------------------------+
|
|
||||||
| [THIS DOC] NAS node |
|
|
||||||
|---------------------------|
|
|
||||||
| WebDAV server |
|
|
||||||
| node agent |
|
|
||||||
| exported directories |
|
|
||||||
| optional tunnel/relay |
|
|
||||||
+---------------------------+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Core decisions
|
## Core decisions
|
||||||
|
|
||||||
- The NAS node should be where WebDAV is served from whenever possible.
|
- 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 as one boring runtime on the user's machine.
|
||||||
- The node should be installable with a Nix module or flake so setup is reproducible.
|
- The node should expose exports, not product semantics.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Choose the WebDAV server we will standardize on for the node.
|
- Define the self-hosted install shape: Docker first, Nix second, or both.
|
||||||
- Define the node agent responsibilities and API back to the control plane.
|
- Define the node identity and enrollment model.
|
||||||
- Define the storage export model: path, label, capacity, tags, protocol support.
|
- Define the storage export model: path, label, tags, permissions, capacity.
|
||||||
- Define direct-access vs relayed-access behavior.
|
- Define when the node self-registers vs when bootstrap tooling registers it.
|
||||||
- Define how the node connects to the cloud/web layer for optional Nextcloud integration.
|
- 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
|
## 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:
|
It should own:
|
||||||
|
|
||||||
|
|
@ -14,8 +15,7 @@ It should own:
|
||||||
- storage exports
|
- storage exports
|
||||||
- access grants
|
- access grants
|
||||||
- mount profiles
|
- mount profiles
|
||||||
- cloud access profiles
|
- later, share flows and audit events
|
||||||
- audit events
|
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
|
|
@ -23,35 +23,32 @@ It should own:
|
||||||
- tracks which NAS nodes exist
|
- tracks which NAS nodes exist
|
||||||
- decides who can access which export
|
- decides who can access which export
|
||||||
- issues mount instructions to local devices
|
- issues mount instructions to local devices
|
||||||
- coordinates optional cloud/web access
|
- drives the web control plane
|
||||||
- stores the operational model of the whole product
|
- stores the operational model of the product
|
||||||
|
|
||||||
## What it should not do
|
## What it should not do
|
||||||
|
|
||||||
- proxy file bytes unless absolutely necessary
|
- proxy file bytes by default
|
||||||
- become a bottleneck in the data path
|
- become the only data path between the Mac and the NAS
|
||||||
- depend on Nextcloud as its system of record
|
- depend on Nextcloud as its source of truth
|
||||||
|
|
||||||
## Diagram
|
## Diagram
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS system
|
self-hosted betterNAS stack
|
||||||
|
|
||||||
NAS node <---------> [THIS DOC] control plane <---------> local device
|
node-service <--------> [THIS DOC] control-server <--------> web control plane
|
||||||
| | |
|
^ |
|
||||||
| | |
|
| |
|
||||||
+---------------------------+-----------------------+-----------+
|
+----------- Finder mount flow -+
|
||||||
|
|
|
||||||
v
|
|
||||||
cloud/web layer
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Core decisions
|
## Core decisions
|
||||||
|
|
||||||
- The control plane is the product brain.
|
- `control-server` is the product brain.
|
||||||
- It should own policy and registry, not storage bytes.
|
- It owns policy and registry, not storage bytes.
|
||||||
- It should stay standalone even if it integrates with Nextcloud.
|
- It should stay deployable on the user's NAS in the default product shape.
|
||||||
- It should issue access decisions, not act like a file server.
|
- The web UI should remain a consumer of this service, not a second backend.
|
||||||
|
|
||||||
## Suggested first entities
|
## Suggested first entities
|
||||||
|
|
||||||
|
|
@ -61,13 +58,12 @@ It should own:
|
||||||
- `StorageExport`
|
- `StorageExport`
|
||||||
- `AccessGrant`
|
- `AccessGrant`
|
||||||
- `MountProfile`
|
- `MountProfile`
|
||||||
- `CloudProfile`
|
|
||||||
- `AuditEvent`
|
- `AuditEvent`
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Define the first real domain model and database schema.
|
- Define the first durable database schema.
|
||||||
- Define auth between user device, NAS node, and control plane.
|
- Define auth between user browser, user device, NAS node, and control-server.
|
||||||
- Define the API for mount profiles and access grants.
|
- Define the API for node registration, export inventory, and mount issuance.
|
||||||
- Define how the control plane tells the cloud/web layer what to expose.
|
- Define how mount tokens or credentials are issued and rotated.
|
||||||
- Define direct-access vs relay behavior for unreachable NAS nodes.
|
- Define what optional cloud/share integration looks like later.
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
# betterNAS Part 3: Local Device
|
# 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
|
## What it is
|
||||||
|
|
||||||
The local device layer is how a user actually mounts and uses their NAS.
|
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
|
- browser opens the web control plane
|
||||||
- manual `Connect to Server`
|
- user gets a WebDAV mount URL
|
||||||
|
- Finder mounts the export
|
||||||
|
|
||||||
It can later grow into:
|
It can later grow into:
|
||||||
|
|
||||||
- a small desktop helper
|
- a small helper app
|
||||||
- one-click mount flows
|
- one-click mount flows
|
||||||
- auto-mount at login
|
- auto-mount at login
|
||||||
- status and reconnect behavior
|
- status and reconnect behavior
|
||||||
|
|
@ -21,52 +23,50 @@ It can later grow into:
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
- authenticates the user to betterNAS
|
- 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
|
- mounts approved storage exports locally
|
||||||
- gives the user a native-feeling way to browse files
|
- gives the user a native-feeling way to browse files
|
||||||
|
|
||||||
## What it should not do
|
## What it should not do
|
||||||
|
|
||||||
- invent its own permissions model
|
- invent its own permissions model
|
||||||
- hardcode NAS endpoints outside the control plane
|
- hardcode node endpoints outside the control-server
|
||||||
- become tightly coupled to Nextcloud
|
- depend on the optional cloud adapter for the core mount flow
|
||||||
|
|
||||||
## Diagram
|
## Diagram
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS system
|
self-hosted betterNAS stack
|
||||||
|
|
||||||
NAS node <---------> control plane <---------> [THIS DOC] local device
|
node-service <--------> control-server <--------> web control plane
|
||||||
| | |
|
^ ^
|
||||||
| | |
|
| |
|
||||||
+---------------------------+-----------------------+-----------+
|
+------------- [THIS DOC] local device ---------+
|
||||||
|
|
browser + Finder
|
||||||
v
|
|
||||||
cloud/web layer
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Core decisions
|
## Core decisions
|
||||||
|
|
||||||
- V1 can rely on native Finder WebDAV mounting.
|
- V1 relies on native Finder WebDAV mounting.
|
||||||
- A lightweight helper app is likely enough before a full custom client.
|
- The web UI should be enough to get the user to a mountable URL.
|
||||||
- The local device should consume mount profiles, not raw infrastructure details.
|
- A lightweight helper app is likely enough before a full native client.
|
||||||
|
|
||||||
## User modes
|
## User modes
|
||||||
|
|
||||||
### Mount mode
|
### Mount mode
|
||||||
|
|
||||||
- user mounts a NAS export into Finder
|
- user mounts a NAS export in Finder
|
||||||
- files are browsed as a mounted remote disk
|
- files are browsed as a mounted remote disk
|
||||||
|
|
||||||
### Cloud mode
|
### Browser mode
|
||||||
|
|
||||||
- user accesses the same storage through browser/mobile/cloud surfaces
|
- user manages the NAS and exports in the web control plane
|
||||||
- this is not the same as a mounted filesystem
|
- optional later: browse files in the browser
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Define the mount profile format the control plane returns.
|
- Define the mount profile format returned by `control-server`.
|
||||||
- Decide what the first local UX is: manual Finder flow, helper app, or both.
|
- Decide whether the first UX is manual Finder flow, helper app, or both.
|
||||||
- Define credential storage and Keychain behavior.
|
- Define credential handling and Keychain behavior.
|
||||||
- Define auto-mount, reconnect, and offline expectations.
|
- Define reconnect and auto-mount expectations.
|
||||||
- Define how the local device hands off to the cloud/web layer when mount mode is not enough.
|
- 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
|
## 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
|
- onboarding
|
||||||
- uploads and downloads
|
- node and export management
|
||||||
- sharing links
|
- mount instructions
|
||||||
- WebDAV-based cloud access
|
- sharing and browser file access later
|
||||||
- mobile reference behavior
|
|
||||||
|
An optional cloud adapter may later provide:
|
||||||
|
|
||||||
|
- Nextcloud-backed browser file UI
|
||||||
|
- mobile-friendly access
|
||||||
|
- share and link workflows
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
- gives users a browser-based file experience
|
- gives users a browser-based entry point into betterNAS
|
||||||
- supports sharing and link-based access
|
- talks only to `control-server`
|
||||||
- gives us a cloud mode in addition to mount mode
|
- exposes the mount flow cleanly
|
||||||
- can act as a reference surface while the main betterNAS product grows
|
- optionally layers on cloud/mobile/share behavior later
|
||||||
|
|
||||||
## What it should not do
|
## What it should not do
|
||||||
|
|
||||||
- own the product system of record
|
- own product state separately from `control-server`
|
||||||
- become the only way users access storage
|
- become the only way users access their storage
|
||||||
- swallow control-plane logic that should stay in betterNAS
|
- make the optional cloud adapter part of the core mount path
|
||||||
|
|
||||||
## Diagram
|
## Diagram
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS system
|
self-hosted betterNAS stack
|
||||||
|
|
||||||
NAS node <---------> control plane <---------> local device
|
node-service <--------> control-server <--------> [THIS DOC] web control plane
|
||||||
| | |
|
^ |
|
||||||
| | |
|
| |
|
||||||
+---------------------------+-----------------------+-----------+
|
+----------- Finder mount flow -+
|
||||||
|
|
|
||||||
v
|
optional later:
|
||||||
+----------------------+
|
Nextcloud adapter / cloud/mobile/share surface
|
||||||
| [THIS DOC] cloud/web |
|
|
||||||
|----------------------|
|
|
||||||
| Nextcloud adapter |
|
|
||||||
| browser UI |
|
|
||||||
| sharing / mobile |
|
|
||||||
+----------------------+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Core decisions
|
## Core decisions
|
||||||
|
|
||||||
- The cloud/web layer is optional but very high leverage.
|
- The web control plane is part of the core product now.
|
||||||
- Nextcloud is a strong fit here because it already gives us file UI and sharing primitives.
|
- Nextcloud is optional and secondary.
|
||||||
- It should sit beside mount mode, not replace it.
|
- 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
|
- sign in
|
||||||
- share and link management
|
- see available NAS nodes
|
||||||
- optional mobile and cloud-drive style access
|
- see available exports
|
||||||
- adapter over the same storage exports the control plane knows about
|
- request mount instructions
|
||||||
|
- copy or launch the WebDAV mount flow
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Decide whether Nextcloud is directly user-facing in v1 or mostly an adapter behind betterNAS.
|
- Define the first user-facing screens for nodes, exports, and mount actions.
|
||||||
- Define how storage exports from the NAS node appear in the cloud/web layer.
|
- Define how auth/session works in the web UI.
|
||||||
- Define how shares in this layer map back to control-plane access grants.
|
- Decide whether browser file viewing is part of V1 or follows later.
|
||||||
- Define what mobile access looks like in v1.
|
- Decide whether Nextcloud remains an internal adapter or becomes user-facing.
|
||||||
- Define branding and how much of the cloud/web layer stays stock vs customized.
|
- Define what sharing means before adding any cloud/mobile layer.
|
||||||
|
|
|
||||||
|
|
@ -12,240 +12,151 @@ It answers four questions:
|
||||||
## The full system
|
## The full system
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS build plan
|
self-hosted betterNAS
|
||||||
|
|
||||||
[2] control plane
|
[3] web control plane
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| API + policy + registry + UI |
|
| onboarding / management / UX |
|
||||||
+--------+---------------+-------+
|
+---------------+----------------+
|
||||||
| |
|
|
|
||||||
control/API | | cloud adapter
|
v
|
||||||
v v
|
[2] control-server
|
||||||
[1] NAS node [4] cloud/web layer
|
+--------------------------------+
|
||||||
+------------------+ +-------------------+
|
| auth / nodes / exports |
|
||||||
| WebDAV + agent | | Nextcloud adapter |
|
| grants / mount profiles |
|
||||||
| real storage | | browser/mobile |
|
+---------------+----------------+
|
||||||
+---------+--------+ +---------+---------+
|
|
|
||||||
| ^
|
v
|
||||||
| mount profile |
|
[1] node-service
|
||||||
v |
|
+--------------------------------+
|
||||||
[3] local device ---------------+
|
| WebDAV + export runtime |
|
||||||
+----------------------+
|
| real storage |
|
||||||
| Finder mount/helper |
|
+---------------+----------------+
|
||||||
| native user entry |
|
^
|
||||||
+----------------------+
|
|
|
||||||
|
[4] local device
|
||||||
|
+--------------------------------+
|
||||||
|
| browser + Finder mount |
|
||||||
|
+--------------------------------+
|
||||||
|
|
||||||
|
optional later:
|
||||||
|
- Nextcloud adapter
|
||||||
|
- hosted control plane
|
||||||
|
- hosted web UI
|
||||||
```
|
```
|
||||||
|
|
||||||
## The core rule
|
## The core rule
|
||||||
|
|
||||||
The control plane owns product semantics.
|
`control-server` owns product semantics.
|
||||||
|
|
||||||
The other three parts are execution surfaces:
|
The other three parts are execution surfaces:
|
||||||
|
|
||||||
- the NAS node serves storage
|
- `node-service` serves storage
|
||||||
- the local device mounts and uses storage
|
- `web control plane` exposes management and mount UX
|
||||||
- the cloud/web layer exposes storage through browser and mobile-friendly flows
|
- `local device` consumes the issued mount flow
|
||||||
|
|
||||||
## What we steal vs write
|
## What we steal vs write
|
||||||
|
|
||||||
| Part | Steal first | Write ourselves |
|
| Part | Steal first | Write ourselves |
|
||||||
| --------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
| ----------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||||
| NAS node | NixOS/Nix module patterns, existing WebDAV servers | node agent, export model, node registration flow |
|
| node-service | Go WebDAV primitives, Docker packaging, later Nix module patterns | node runtime, export model, node enrollment |
|
||||||
| Control plane | Go stdlib routing, pgx/sqlc, go-redis/asynq, OpenAPI codegen | product domain model, policy engine, mount/cloud APIs, registry |
|
| control-server | Go stdlib routing, pgx/sqlc, Redis helpers, OpenAPI codegen | product domain model, policy engine, mount APIs, registry |
|
||||||
| Local device | Finder WebDAV mount, macOS Keychain, later maybe launch agent patterns | helper app, mount profile handling, auto-mount UX |
|
| web control plane | Next.js app conventions, shared UI primitives | product UI, onboarding, node/export flows, 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 |
|
| 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
|
## Where each part should start
|
||||||
|
|
||||||
## 1. NAS node
|
## 1. node-service
|
||||||
|
|
||||||
Start from:
|
Start from:
|
||||||
|
|
||||||
- Nix flake / module
|
- one Go binary
|
||||||
- a standard WebDAV server
|
- one export root
|
||||||
- a very small agent process
|
- one WebDAV surface
|
||||||
|
- one deployable self-hosted runtime
|
||||||
|
|
||||||
Do not start by writing:
|
Do not start by writing:
|
||||||
|
|
||||||
- custom storage protocol
|
- a custom storage protocol
|
||||||
- custom file server
|
- a custom sync engine
|
||||||
- custom sync engine
|
- a complex relay stack
|
||||||
|
|
||||||
The NAS node should be boring and reproducible.
|
## 2. control-server
|
||||||
|
|
||||||
## 2. Control plane
|
|
||||||
|
|
||||||
Start from:
|
Start from:
|
||||||
|
|
||||||
- Go
|
- Go
|
||||||
- standard library routing first
|
- one API
|
||||||
- Postgres via `pgx` and `sqlc`
|
- one durable data model
|
||||||
- Redis via `go-redis`
|
- node registration and mount profile issuance
|
||||||
- OpenAPI-driven contracts
|
|
||||||
- standalone API mindset
|
|
||||||
|
|
||||||
Do not start by writing:
|
Do not start by writing:
|
||||||
|
|
||||||
- microservices
|
- microservices
|
||||||
- custom file transport
|
- file proxying by default
|
||||||
- a proxy that sits in the middle of every file transfer
|
- hosted-only assumptions
|
||||||
|
|
||||||
This is the first real thing we should build.
|
## 3. web control plane
|
||||||
|
|
||||||
## 3. Local device
|
|
||||||
|
|
||||||
Start from:
|
Start from:
|
||||||
|
|
||||||
- native Finder `Connect to Server`
|
- sign in
|
||||||
- WebDAV mount URLs issued by the control plane
|
- 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:
|
Then later add:
|
||||||
|
|
||||||
- a lightweight helper app
|
- one-click helper
|
||||||
- Keychain integration
|
- Keychain integration
|
||||||
- auto-mount at login
|
- 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
|
## 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
|
1. node-service exposes a directory over WebDAV
|
||||||
2. control plane can register the node and its exports
|
2. control-server registers the node and its exports
|
||||||
3. local device can mount that export in Finder
|
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
|
### Phase C: make deployment real
|
||||||
2. add auth and policy
|
|
||||||
3. add a simple standalone web UI for admin/control use
|
|
||||||
|
|
||||||
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
|
1. add Nextcloud only if browser/share/mobile value justifies it
|
||||||
2. expose browser/mobile/share flows
|
2. keep it out of the critical mount path
|
||||||
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.
|
|
||||||
|
|
||||||
## Build goal for V1
|
## Build goal for V1
|
||||||
|
|
||||||
V1 should prove one clean loop:
|
V1 should prove one clean loop:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
user picks NAS export in betterNAS UI
|
user opens betterNAS web UI
|
||||||
-> control plane issues mount profile
|
-> sees a registered export
|
||||||
-> local device mounts WebDAV export
|
-> requests mount instructions
|
||||||
-> user sees and uses files in Finder
|
-> Finder mounts the WebDAV export
|
||||||
-> optional Nextcloud surface exposes the same storage in cloud mode
|
-> 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.
|
This file is the canonical contract for the repository.
|
||||||
|
|
||||||
If the planning docs, scaffold code, or future tasks disagree, this file and
|
If the planning docs, scaffold code, or future tasks disagree, this file and
|
||||||
[`packages/contracts`](../packages/contracts)
|
[`packages/contracts`](../packages/contracts) win.
|
||||||
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
|
For the current product shape, the user should be able to run the whole stack on
|
||||||
- lock the shared contracts
|
their NAS machine:
|
||||||
- define one end-to-end verification loop
|
|
||||||
- enforce clear ownership boundaries
|
|
||||||
|
|
||||||
That first task should leave the repo in a state where later work can be
|
- `node-service` serves the real files over WebDAV
|
||||||
parallelized without interface drift.
|
- `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
|
```text
|
||||||
betterNAS canonical contract
|
betterNAS canonical contract
|
||||||
|
|
||||||
[2] control plane
|
self-hosted on user's NAS
|
||||||
+-----------------------------------+
|
|
||||||
| system of record |
|
+--------------------------------------+
|
||||||
| users / devices / nodes / grants |
|
| [2] control-server |
|
||||||
| mount profiles / cloud profiles |
|
| system of record |
|
||||||
+---------+---------------+---------+
|
| auth / nodes / exports / grants |
|
||||||
| |
|
| mount sessions / audit |
|
||||||
control/API | | cloud adapter
|
+------------------+-------------------+
|
||||||
v v
|
|
|
||||||
[1] NAS node [4] cloud / web layer
|
v
|
||||||
+-------------------+ +----------------------+
|
+--------------------------------------+
|
||||||
| WebDAV + node | | Nextcloud adapter |
|
| [1] node-service |
|
||||||
| real file bytes | | browser / mobile |
|
| WebDAV export runtime |
|
||||||
+---------+---------+ +----------+-----------+
|
| real file bytes |
|
||||||
| ^
|
+------------------+-------------------+
|
||||||
| mount profile |
|
^
|
||||||
v |
|
|
|
||||||
[3] local device --------------+
|
+------------------+-------------------+
|
||||||
+----------------------+
|
| [3] web control plane |
|
||||||
| Finder mount/helper |
|
| onboarding / management / mount UX |
|
||||||
| native user entry |
|
+------------------+-------------------+
|
||||||
+----------------------+
|
^
|
||||||
|
|
|
||||||
|
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
|
## Non-negotiable rules
|
||||||
|
|
||||||
1. The control plane is the system of record.
|
1. `control-server` is the system of record.
|
||||||
2. File bytes should flow as directly as possible between the NAS node and the
|
2. `node-service` serves the bytes.
|
||||||
local device.
|
3. `web control plane` is a UI over `control-server`, not a second policy
|
||||||
3. The control plane should issue policy, grants, and profiles. It should not
|
backend.
|
||||||
become the default file proxy.
|
4. The main data path should be `local device <-> node-service` whenever
|
||||||
4. The NAS node should serve WebDAV directly whenever possible.
|
possible.
|
||||||
5. The local device consumes mount profiles. It does not hardcode infra details.
|
5. `control-server` should issue access, grants, and mount profiles. It should
|
||||||
6. The cloud/web layer is optional and secondary. Nextcloud is an adapter, not
|
not become the default file proxy.
|
||||||
the product center.
|
6. The self-hosted stack should work without Nextcloud.
|
||||||
|
7. Nextcloud, if used, is an optional adapter and secondary surface.
|
||||||
|
|
||||||
## Canonical sources of truth
|
## Canonical sources of truth
|
||||||
|
|
||||||
|
|
@ -67,7 +82,7 @@ Use these in this order:
|
||||||
for boundaries, ownership, and delivery rules
|
for boundaries, ownership, and delivery rules
|
||||||
2. [`packages/contracts`](../packages/contracts)
|
2. [`packages/contracts`](../packages/contracts)
|
||||||
for machine-readable types, schemas, and route constants
|
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/01-nas-node.md`](./01-nas-node.md)
|
||||||
- [`docs/02-control-plane.md`](./02-control-plane.md)
|
- [`docs/02-control-plane.md`](./02-control-plane.md)
|
||||||
- [`docs/03-local-device.md`](./03-local-device.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)
|
- [`apps/nextcloud-app`](../apps/nextcloud-app)
|
||||||
- [`packages/contracts`](../packages/contracts)
|
- [`packages/contracts`](../packages/contracts)
|
||||||
|
|
||||||
Every parallel task should primarily stay inside one of those lanes unless it is
|
The first three are core. `apps/nextcloud-app` is optional and should not drive
|
||||||
an explicit contract task.
|
the main architecture.
|
||||||
|
|
||||||
## The contract surface we need first
|
## The contract surface we need first
|
||||||
|
|
||||||
The first shared contract set should cover only the seams that let all four
|
The first shared contract set should cover only the seams needed for the
|
||||||
parts exist at once.
|
self-hosted mount flow.
|
||||||
|
|
||||||
### NAS node -> control plane
|
### Node-service -> control-server
|
||||||
|
|
||||||
- node registration
|
- node registration
|
||||||
- node heartbeat
|
- node heartbeat
|
||||||
- export inventory
|
- 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 mount profile
|
||||||
|
- issue share or cloud profile later
|
||||||
|
|
||||||
### Cloud/web layer -> control plane
|
### Local device -> control-server
|
||||||
|
|
||||||
- issue cloud profile
|
- fetch mount instructions
|
||||||
- read export metadata
|
- receive issued WebDAV URL and credentials or token material
|
||||||
|
|
||||||
### Control plane internal
|
### Control-server internal
|
||||||
|
|
||||||
- health
|
- health
|
||||||
- version
|
- version
|
||||||
|
|
@ -117,57 +134,61 @@ parts exist at once.
|
||||||
- `StorageExport`
|
- `StorageExport`
|
||||||
- `AccessGrant`
|
- `AccessGrant`
|
||||||
- `MountProfile`
|
- `MountProfile`
|
||||||
- `CloudProfile`
|
- `AuditEvent`
|
||||||
|
|
||||||
## Parallel work boundaries
|
## 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 |
|
The shared write surface across parts should stay narrow:
|
||||||
| --------------- | ------------------------------------------------ | ----------------------------- | ------------------------------ |
|
|
||||||
| 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:
|
|
||||||
|
|
||||||
- [`packages/contracts`](../packages/contracts)
|
- [`packages/contracts`](../packages/contracts)
|
||||||
- this file when the architecture contract changes
|
- this file when architecture changes
|
||||||
|
|
||||||
## Verification loop
|
## 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
|
```text
|
||||||
[1] mock or real NAS node exposes a WebDAV export
|
[node-service]
|
||||||
-> [2] control plane registers the node and export
|
serves a WebDAV export
|
||||||
-> [3] local device asks for a mount profile
|
|
|
||||||
-> [3] local device receives a WebDAV mount URL
|
v
|
||||||
-> user can mount the export in Finder
|
[control-server]
|
||||||
-> [4] optional cloud/web layer can expose the same export in cloud mode
|
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
|
If a task does not make one of those steps more real, it is probably too early.
|
||||||
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 self-hosted stack boots locally
|
||||||
- the control plane can represent nodes, exports, grants, and profiles
|
- the control-server can represent nodes, exports, grants, and mount profiles
|
||||||
- the contracts package exports the first shared shapes and schemas
|
- the node-service serves a real WebDAV export
|
||||||
- local verification can prove the mount-profile loop end to end
|
- the web control plane can expose the mount flow
|
||||||
- future agents can work inside one part without inventing new interfaces
|
- a local Mac can mount the export in Finder
|
||||||
|
|
||||||
## Rules for future tasks and agents
|
## Rules for future tasks and agents
|
||||||
|
|
||||||
1. No part may invent private request or response shapes for shared flows.
|
1. No part may invent private request or response shapes for shared flows.
|
||||||
2. Contract changes must update
|
2. Contract changes must update [`packages/contracts`](../packages/contracts)
|
||||||
[`packages/contracts`](../packages/contracts)
|
|
||||||
first.
|
first.
|
||||||
3. Architecture changes must update this file in the same change.
|
3. Architecture changes must update this file in the same change.
|
||||||
4. Additive contract changes are preferred over breaking ones.
|
4. Additive contract changes are preferred over breaking ones.
|
||||||
5. New tasks should target one part at a time unless they are explicitly
|
5. Prioritize the self-hosted mount loop before optional cloud/mobile work.
|
||||||
contract tasks.
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,55 @@
|
||||||
# betterNAS References
|
# 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`
|
### Node-service and WebDAV
|
||||||
- repo: https://github.com/rclone/rclone
|
|
||||||
- why: fast way to stand up a WebDAV layer over existing storage
|
- Go WebDAV package
|
||||||
|
- docs: https://pkg.go.dev/golang.org/x/net/webdav
|
||||||
|
- why: embeddable WebDAV implementation for the NAS runtime
|
||||||
|
|
||||||
- `hacdias/webdav`
|
- `hacdias/webdav`
|
||||||
- repo: https://github.com/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`
|
- `rclone serve webdav`
|
||||||
- docs: https://httpd.apache.org/docs/current/mod/mod_dav.html
|
- repo: https://github.com/rclone/rclone
|
||||||
- why: standard WebDAV implementation if we want conventional infra
|
- why: useful reference for standing up WebDAV over existing storage
|
||||||
|
|
||||||
### Nix / host configuration
|
### Self-hosting and NAS configuration
|
||||||
|
|
||||||
- NixOS manual
|
- NixOS manual
|
||||||
- docs: https://nixos.org/manual/nixos/stable/
|
- 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
|
- Nixpkgs
|
||||||
- repo: https://github.com/NixOS/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
|
### Backend and infra references
|
||||||
|
|
||||||
- Go routing enhancements
|
- Go routing enhancements
|
||||||
- docs: https://go.dev/blog/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`
|
- `chi`
|
||||||
- repo: https://github.com/go-chi/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
|
- PostgreSQL
|
||||||
- docs: https://www.postgresql.org/docs/
|
- 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`
|
- `pgx`
|
||||||
- repo: https://github.com/jackc/pgx
|
- repo: https://github.com/jackc/pgx
|
||||||
- why: Postgres-first Go driver and toolkit
|
- why: Postgres-first Go driver
|
||||||
|
|
||||||
- `sqlc`
|
- `sqlc`
|
||||||
- repo: https://github.com/sqlc-dev/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
|
- Redis
|
||||||
- docs: https://redis.io/docs/latest/
|
- docs: https://redis.io/docs/latest/
|
||||||
- why: cache, jobs, ephemeral coordination
|
- why: cache, jobs, and ephemeral coordination
|
||||||
|
|
||||||
- `go-redis`
|
- `go-redis`
|
||||||
- repo: https://github.com/redis/go-redis
|
- repo: https://github.com/redis/go-redis
|
||||||
- why: primary Redis client for Go
|
- why: primary Redis client
|
||||||
|
|
||||||
- `asynq`
|
- `asynq`
|
||||||
- repo: https://github.com/hibiken/asynq
|
- repo: https://github.com/hibiken/asynq
|
||||||
- why: practical Redis-backed background jobs
|
- 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`
|
- `oapi-codegen`
|
||||||
- repo: https://github.com/oapi-codegen/oapi-codegen
|
- repo: https://github.com/oapi-codegen/oapi-codegen
|
||||||
- why: generate Go and TS surfaces from OpenAPI with less drift
|
- why: generate Go and TS surfaces from OpenAPI with less drift
|
||||||
|
|
||||||
### SSH access / gateway reference
|
## Primary now: web control plane and local device
|
||||||
|
|
||||||
- `sshpiper`
|
### Web control plane
|
||||||
- repo: https://github.com/tg123/sshpiper
|
|
||||||
- why: SSH proxy/gateway reference if we add SSH-brokered access later
|
|
||||||
|
|
||||||
## 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`
|
- Apple Finder `Connect to Server`
|
||||||
- docs: https://support.apple.com/en-lamr/guide/mac-help/mchlp3015/mac
|
- 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
|
- Apple Finder WebDAV mounting
|
||||||
- docs: https://support.apple.com/is-is/guide/mac-help/mchlp1546/mac
|
- docs: https://support.apple.com/is-is/guide/mac-help/mchlp1546/mac
|
||||||
- why: direct WebDAV mount behavior in Finder
|
- why: direct WebDAV mount behavior in Finder
|
||||||
|
|
||||||
### macOS integration references
|
|
||||||
|
|
||||||
- Apple developer docs
|
- Apple developer docs
|
||||||
- docs: https://developer.apple.com/documentation/
|
- 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
|
- Keychain data protection
|
||||||
- docs: https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web
|
- docs: https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web
|
||||||
- why: baseline secret-storage model for device credentials
|
- 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
|
- WebDAV RFC 4918
|
||||||
- docs: https://www.rfc-editor.org/rfc/rfc4918
|
- docs: https://www.rfc-editor.org/rfc/rfc4918
|
||||||
- why: protocol semantics and caveats
|
- why: protocol semantics and caveats
|
||||||
|
|
||||||
## Cloud / web layer
|
## Optional later: cloud adapter
|
||||||
|
|
||||||
### Nextcloud server and app references
|
### Nextcloud server and app references
|
||||||
|
|
||||||
- Nextcloud server
|
- Nextcloud server
|
||||||
- repo: https://github.com/nextcloud/server
|
- repo: https://github.com/nextcloud/server
|
||||||
- why: cloud/web/share substrate
|
- why: optional browser/share/mobile substrate
|
||||||
|
|
||||||
- Nextcloud app template
|
- Nextcloud app template
|
||||||
- repo: https://github.com/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
|
- Nextcloud AppAPI / ExApps
|
||||||
- docs: https://docs.nextcloud.com/server/latest/admin_manual/exapps_management/AppAPIAndExternalApps.html
|
- docs: https://docs.nextcloud.com/server/latest/admin_manual/exapps_management/AppAPIAndExternalApps.html
|
||||||
- why: external app integration model
|
- 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
|
- Nextcloud WebDAV access
|
||||||
- docs: https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html
|
- docs: https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html
|
||||||
- why: protocol and client behavior reference
|
- 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
|
- docs: https://docs.nextcloud.com/server/latest/user_manual/en/external_storage/external_storage.html
|
||||||
- why: storage aggregation reference
|
- 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
|
## Working rule
|
||||||
|
|
||||||
Use these references in this order:
|
Use these references in this order:
|
||||||
|
|
||||||
1. steal primitives that already solve boring problems
|
1. steal primitives that solve the self-hosted DAV problem first
|
||||||
2. adapt them at the control-plane boundary
|
2. adapt them at the control-server boundary
|
||||||
3. only fork or replace when the product meaningfully diverges
|
3. only pull in optional cloud layers when the core mount product is solid
|
||||||
|
|
|
||||||
189
skeleton.md
189
skeleton.md
|
|
@ -7,17 +7,17 @@ Its job is simple:
|
||||||
- lock the repo shape
|
- lock the repo shape
|
||||||
- lock the language per runtime
|
- lock the language per runtime
|
||||||
- lock the first shared contract surface
|
- lock the first shared contract surface
|
||||||
- give agents a safe place to work in parallel
|
- keep the self-hosted stack clear
|
||||||
- keep the list of upstream references we are stealing from
|
- make later scoped execution runs easier
|
||||||
|
|
||||||
## Repo shape
|
## Repo shape
|
||||||
|
|
||||||
```text
|
```text
|
||||||
betterNAS/
|
betterNAS/
|
||||||
├── apps/
|
├── apps/
|
||||||
│ ├── web/ # Next.js control-plane UI
|
│ ├── web/ # Next.js web control plane
|
||||||
│ ├── control-plane/ # Go control-plane API
|
│ ├── control-plane/ # Go control-server
|
||||||
│ ├── node-agent/ # Go NAS runtime + WebDAV surface
|
│ ├── node-agent/ # Go node-service and WebDAV runtime
|
||||||
│ └── nextcloud-app/ # optional Nextcloud adapter
|
│ └── nextcloud-app/ # optional Nextcloud adapter
|
||||||
├── packages/
|
├── packages/
|
||||||
│ ├── contracts/ # canonical OpenAPI, schemas, TS types
|
│ ├── contracts/ # canonical OpenAPI, schemas, TS types
|
||||||
|
|
@ -25,23 +25,64 @@ betterNAS/
|
||||||
│ ├── eslint-config/ # shared lint config
|
│ ├── eslint-config/ # shared lint config
|
||||||
│ └── typescript-config/ # shared TS config
|
│ └── typescript-config/ # shared TS config
|
||||||
├── infra/
|
├── infra/
|
||||||
│ └── docker/ # local runtime stack
|
│ └── docker/ # self-hosted stack for local proof
|
||||||
├── docs/ # architecture and part docs
|
├── docs/ # architecture and build docs
|
||||||
├── scripts/ # local helper scripts
|
├── scripts/ # bootstrap, verify, and stack helpers
|
||||||
├── go.work # Go workspace
|
├── go.work # Go workspace
|
||||||
├── turbo.json # Turborepo task graph
|
├── turbo.json # Turborepo task graph
|
||||||
└── skeleton.md # this file
|
└── skeleton.md # this file
|
||||||
```
|
```
|
||||||
|
|
||||||
## Runtime and language choices
|
## Runtime and language choices
|
||||||
|
|
||||||
| Part | Language | Why |
|
| Part | Language | Why |
|
||||||
| -------------------- | ---------------------------------- | -------------------------------------------------------------------- |
|
| -------------------- | ---------------------------------- | ------------------------------------------------------------------- |
|
||||||
| `apps/web` | TypeScript + Next.js | best UI velocity, best admin/control-plane UX |
|
| `apps/web` | TypeScript + Next.js | fastest way to build the control-plane UI |
|
||||||
| `apps/control-plane` | Go | strong concurrency, static binaries, operationally simple |
|
| `apps/control-plane` | Go | strong backend baseline, static binaries, simple self-hosting |
|
||||||
| `apps/node-agent` | Go | best fit for host runtime, WebDAV service, and future Nix deployment |
|
| `apps/node-agent` | Go | best fit for NAS runtime, WebDAV serving, and future Nix deployment |
|
||||||
| `apps/nextcloud-app` | PHP | native language for the Nextcloud adapter surface |
|
| `apps/nextcloud-app` | PHP | native language for an optional Nextcloud adapter |
|
||||||
| `packages/contracts` | OpenAPI + JSON Schema + TypeScript | language-neutral source of truth with practical TS ergonomics |
|
| `packages/contracts` | OpenAPI + JSON Schema + TypeScript | language-neutral source of truth with practical frontend ergonomics |
|
||||||
|
|
||||||
|
## Default deployment model
|
||||||
|
|
||||||
|
The default product story is self-hosted:
|
||||||
|
|
||||||
|
```text
|
||||||
|
self-hosted betterNAS stack on user's NAS
|
||||||
|
|
||||||
|
+--------------------------------------------+
|
||||||
|
| web control plane |
|
||||||
|
| user opens this in browser |
|
||||||
|
+-------------------+------------------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+--------------------------------------------+
|
||||||
|
| control-server |
|
||||||
|
| auth / nodes / exports / grants |
|
||||||
|
| mount profile issuance |
|
||||||
|
+-------------------+------------------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+--------------------------------------------+
|
||||||
|
| node-service |
|
||||||
|
| WebDAV export runtime |
|
||||||
|
| real NAS files |
|
||||||
|
+--------------------------------------------+
|
||||||
|
|
||||||
|
user Mac
|
||||||
|
|
|
||||||
|
+--> browser -> web control plane
|
||||||
|
|
|
||||||
|
+--> Finder -> issued WebDAV mount URL
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional later shape:
|
||||||
|
|
||||||
|
- hosted control-server
|
||||||
|
- hosted web control plane
|
||||||
|
- optional Nextcloud adapter for cloud/mobile/share surfaces
|
||||||
|
|
||||||
|
Those are not required for the core betterNAS product loop.
|
||||||
|
|
||||||
## Canonical contract rule
|
## Canonical contract rule
|
||||||
|
|
||||||
|
|
@ -52,39 +93,38 @@ The source of truth for shared interfaces is:
|
||||||
3. [`packages/contracts/schemas`](./packages/contracts/schemas)
|
3. [`packages/contracts/schemas`](./packages/contracts/schemas)
|
||||||
4. [`packages/contracts/src`](./packages/contracts/src)
|
4. [`packages/contracts/src`](./packages/contracts/src)
|
||||||
|
|
||||||
Agents must not invent private shared request or response shapes outside those
|
Agents must not invent shared request or response shapes outside those
|
||||||
locations.
|
locations.
|
||||||
|
|
||||||
## Parallel lanes
|
## Implementation lanes
|
||||||
|
|
||||||
```text
|
```text
|
||||||
shared write surface
|
shared write surface
|
||||||
+-------------------------------------------+
|
+-------------------------------------------+
|
||||||
| docs/architecture.md |
|
| docs/architecture.md |
|
||||||
| packages/contracts/ |
|
| packages/contracts/ |
|
||||||
+----------------+--------------------------+
|
+----------------+--------------------------+
|
||||||
|
|
|
|
||||||
+-----------------+-----------------+-----------------+
|
+---------------+----------------+----------------+
|
||||||
| | | |
|
| | |
|
||||||
v v v v
|
v v v
|
||||||
NAS node control plane local device cloud layer
|
node-service control-server web control plane
|
||||||
lane lane lane lane
|
|
||||||
|
optional later:
|
||||||
|
nextcloud adapter
|
||||||
```
|
```
|
||||||
|
|
||||||
Allowed ownership:
|
Allowed ownership:
|
||||||
|
|
||||||
- NAS node lane
|
- node-service lane
|
||||||
- `apps/node-agent`
|
- `apps/node-agent`
|
||||||
- future `infra/nix/node-*`
|
- future `infra/nix` host module work
|
||||||
- control-plane lane
|
- control-server lane
|
||||||
- `apps/control-plane`
|
- `apps/control-plane`
|
||||||
- DB and queue integration code later
|
- web control plane lane
|
||||||
- local-device lane
|
- `apps/web`
|
||||||
- mount docs first
|
- optional adapter lane
|
||||||
- future helper app
|
|
||||||
- cloud layer lane
|
|
||||||
- `apps/nextcloud-app`
|
- `apps/nextcloud-app`
|
||||||
- Nextcloud mapping logic
|
|
||||||
- shared contract lane
|
- shared contract lane
|
||||||
- `packages/contracts`
|
- `packages/contracts`
|
||||||
- `docs/architecture.md`
|
- `docs/architecture.md`
|
||||||
|
|
@ -92,24 +132,24 @@ Allowed ownership:
|
||||||
## The first verification loop
|
## The first verification loop
|
||||||
|
|
||||||
```text
|
```text
|
||||||
[node-agent]
|
[node-service]
|
||||||
serves WebDAV export
|
serves WebDAV export
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
[control-plane]
|
[control-server]
|
||||||
registers node + export
|
registers node + export
|
||||||
issues mount profile
|
issues mount profile
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
[local device]
|
[web control plane]
|
||||||
mounts WebDAV in Finder
|
shows export and mount action
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
[cloud layer]
|
[local device]
|
||||||
optionally exposes same export in Nextcloud
|
mounts in Finder
|
||||||
```
|
```
|
||||||
|
|
||||||
If a task does not make one of those steps more real, it is probably too early.
|
This is the main product loop.
|
||||||
|
|
||||||
## Upstream references to steal from
|
## Upstream references to steal from
|
||||||
|
|
||||||
|
|
@ -125,18 +165,14 @@ If a task does not make one of those steps more real, it is probably too early.
|
||||||
|
|
||||||
- Next.js backend-for-frontend guide
|
- Next.js backend-for-frontend guide
|
||||||
- https://nextjs.org/docs/app/guides/backend-for-frontend
|
- https://nextjs.org/docs/app/guides/backend-for-frontend
|
||||||
- why: keep Next.js as UI/BFF, not the system-of-record backend
|
- why: keep Next.js as UI and orchestration surface, not the source-of-truth backend
|
||||||
|
|
||||||
### Go control plane
|
### Go control-server
|
||||||
|
|
||||||
- Go routing enhancements
|
- Go routing enhancements
|
||||||
- https://go.dev/blog/routing-enhancements
|
- https://go.dev/blog/routing-enhancements
|
||||||
- why: stdlib-first routing baseline
|
- why: stdlib-first routing baseline
|
||||||
|
|
||||||
- `chi`
|
|
||||||
- https://github.com/go-chi/chi
|
|
||||||
- why: minimal router if stdlib patterns become too bare
|
|
||||||
|
|
||||||
- `pgx`
|
- `pgx`
|
||||||
- https://github.com/jackc/pgx
|
- https://github.com/jackc/pgx
|
||||||
- why: Postgres-first Go driver
|
- why: Postgres-first Go driver
|
||||||
|
|
@ -153,23 +189,11 @@ If a task does not make one of those steps more real, it is probably too early.
|
||||||
- https://github.com/hibiken/asynq
|
- https://github.com/hibiken/asynq
|
||||||
- why: practical Redis-backed job system
|
- why: practical Redis-backed job system
|
||||||
|
|
||||||
- `koanf`
|
|
||||||
- https://github.com/knadh/koanf
|
|
||||||
- why: layered config if env-only config becomes too small
|
|
||||||
|
|
||||||
- `envconfig`
|
|
||||||
- https://github.com/kelseyhightower/envconfig
|
|
||||||
- why: tiny env-only config option
|
|
||||||
|
|
||||||
- `log/slog`
|
|
||||||
- https://pkg.go.dev/log/slog
|
|
||||||
- why: structured logging without adding a logging framework first
|
|
||||||
|
|
||||||
- `oapi-codegen`
|
- `oapi-codegen`
|
||||||
- https://github.com/oapi-codegen/oapi-codegen
|
- https://github.com/oapi-codegen/oapi-codegen
|
||||||
- why: generate Go and TS surfaces from OpenAPI
|
- why: generate surfaces from OpenAPI with less drift
|
||||||
|
|
||||||
### NAS node and WebDAV
|
### Node-service and WebDAV
|
||||||
|
|
||||||
- Go WebDAV package
|
- Go WebDAV package
|
||||||
- https://pkg.go.dev/golang.org/x/net/webdav
|
- https://pkg.go.dev/golang.org/x/net/webdav
|
||||||
|
|
@ -183,11 +207,7 @@ If a task does not make one of those steps more real, it is probably too early.
|
||||||
- https://nixos.org/manual/nixos/stable/
|
- https://nixos.org/manual/nixos/stable/
|
||||||
- why: declarative host setup and service wiring
|
- why: declarative host setup and service wiring
|
||||||
|
|
||||||
- Nixpkgs
|
### Local mount UX
|
||||||
- https://github.com/NixOS/nixpkgs
|
|
||||||
- why: service module and packaging reference
|
|
||||||
|
|
||||||
### Local device and mount UX
|
|
||||||
|
|
||||||
- Finder `Connect to Server`
|
- Finder `Connect to Server`
|
||||||
- https://support.apple.com/en-lamr/guide/mac-help/mchlp3015/mac
|
- https://support.apple.com/en-lamr/guide/mac-help/mchlp3015/mac
|
||||||
|
|
@ -201,36 +221,20 @@ If a task does not make one of those steps more real, it is probably too early.
|
||||||
- https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web
|
- https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web
|
||||||
- why: local credential storage model
|
- why: local credential storage model
|
||||||
|
|
||||||
- Finder Sync extensions
|
|
||||||
- https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/Finder.html
|
|
||||||
- why: future helper app / Finder integration reference
|
|
||||||
|
|
||||||
- WebDAV RFC 4918
|
- WebDAV RFC 4918
|
||||||
- https://www.rfc-editor.org/rfc/rfc4918
|
- https://www.rfc-editor.org/rfc/rfc4918
|
||||||
- why: protocol semantics and edge cases
|
- why: protocol semantics and edge cases
|
||||||
|
|
||||||
### Cloud and adapter layer
|
### Optional cloud adapter
|
||||||
|
|
||||||
- Nextcloud app template
|
- Nextcloud app template
|
||||||
- https://github.com/nextcloud/app_template
|
- https://github.com/nextcloud/app_template
|
||||||
- why: thin adapter app reference
|
- why: thin adapter app reference
|
||||||
|
|
||||||
- AppAPI / External Apps
|
|
||||||
- https://docs.nextcloud.com/server/latest/admin_manual/exapps_management/AppAPIAndExternalApps.html
|
|
||||||
- why: official external-app integration path
|
|
||||||
|
|
||||||
- Nextcloud WebDAV docs
|
- Nextcloud WebDAV docs
|
||||||
- https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html
|
- https://docs.nextcloud.com/server/latest/user_manual/en/files/access_webdav.html
|
||||||
- why: protocol/client behavior reference
|
- why: protocol/client behavior reference
|
||||||
|
|
||||||
- Nextcloud external storage
|
|
||||||
- https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/external_storage_configuration_gui.html
|
|
||||||
- why: storage aggregation behavior
|
|
||||||
|
|
||||||
- Nextcloud file sharing config
|
|
||||||
- https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/file_sharing_configuration.html
|
|
||||||
- why: share semantics reference
|
|
||||||
|
|
||||||
## What we steal vs what we own
|
## What we steal vs what we own
|
||||||
|
|
||||||
### Steal
|
### Steal
|
||||||
|
|
@ -240,22 +244,21 @@ If a task does not make one of those steps more real, it is probably too early.
|
||||||
- Go stdlib and proven Go infra libraries
|
- Go stdlib and proven Go infra libraries
|
||||||
- Go WebDAV implementation
|
- Go WebDAV implementation
|
||||||
- Finder native WebDAV mount UX
|
- Finder native WebDAV mount UX
|
||||||
- Nextcloud shell-app and cloud/web primitives
|
- optional Nextcloud adapter primitives later
|
||||||
|
|
||||||
### Own
|
### Own
|
||||||
|
|
||||||
- the betterNAS domain model
|
- the betterNAS domain model
|
||||||
- the control-plane API
|
- the control-server API
|
||||||
- the node registration and export model
|
- the node registration and export model
|
||||||
- the mount profile model
|
- the mount profile model
|
||||||
- the mapping between cloud mode and mount mode
|
- the self-hosted stack wiring
|
||||||
- the repo contract and shared schemas
|
- the repo contract and shared schemas
|
||||||
- the root `pnpm verify` loop
|
- the root `pnpm verify` loop
|
||||||
|
|
||||||
## The first implementation slices after this scaffold
|
## The next implementation slices
|
||||||
|
|
||||||
1. make `apps/node-agent` serve a real configurable WebDAV export
|
1. make `apps/web` expose the real mount flow to a user
|
||||||
2. make `apps/control-plane` store real node/export records
|
2. add durable control-server storage for nodes, exports, and grants
|
||||||
3. issue real mount profiles from the control plane
|
3. define the self-hosted NAS install shape for `apps/node-agent`
|
||||||
4. make `apps/web` let a user pick an export and request a profile
|
4. keep the optional cloud adapter out of the critical path
|
||||||
5. keep `apps/nextcloud-app` thin and optional
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue