698 lines
16 KiB
Markdown
698 lines
16 KiB
Markdown
# Remote Client Shares V1.1 Design
|
|
|
|
## Doel
|
|
|
|
Een gebruiker van WebManager moet naast de bestaande server-side storage-roots ook een beperkte set lokale mappen van zijn eigen client-Mac kunnen benaderen, zonder de hele homefolder bloot te geven.
|
|
|
|
Voorbeelden van toegestane client-shares:
|
|
|
|
- `Downloads`
|
|
- `Movies`
|
|
- `Pictures`
|
|
|
|
De oplossing moet:
|
|
|
|
- simpel blijven
|
|
- veilig blijven
|
|
- de bestaande storage-workflow niet breken
|
|
- WebManager niet laten vastlopen als een remote helper-agent offline is
|
|
|
|
---
|
|
|
|
## Kernbeslissingen voor V1.1
|
|
|
|
Deze beslissingen liggen in V1.1 vast.
|
|
|
|
- Remote client shares worden niet opgenomen in `root_aliases`.
|
|
- `/Clients` wordt een aparte virtuele bron naast `/Volumes`.
|
|
- Remote paden lopen niet door de bestaande lokale filesystem-resolutie.
|
|
- `client_id` is intern de enige leidende identiteit.
|
|
- `display_name` is alleen voor UI-weergave.
|
|
- De agent werkt alleen met `share key + relatief pad`.
|
|
- Alle agent-calls vereisen authenticatie, niet alleen registratie.
|
|
- Offline agents mogen alleen hun eigen subtree beïnvloeden, nooit de rest van de app.
|
|
- V1 blijft read-mostly: registry, browse, info, preview, download.
|
|
|
|
---
|
|
|
|
## Waarom niet als gewone root alias
|
|
|
|
De huidige backend gaat uit van server-side whitelisted filesystem roots.
|
|
|
|
Dat model werkt voor:
|
|
|
|
- `/Volumes/...`
|
|
- gemounte server storage
|
|
- container-side toegankelijke paden
|
|
|
|
Dat model werkt niet goed voor:
|
|
|
|
- de lokale schijf van de browsergebruiker
|
|
- een remote Mac die buiten de server draait
|
|
- clients die offline kunnen zijn
|
|
- clients die dynamische IP-adressen hebben
|
|
|
|
Daarom mogen remote client shares niet in hetzelfde model worden gestopt als `root_aliases`.
|
|
|
|
---
|
|
|
|
## Scope V1.1
|
|
|
|
### In scope
|
|
|
|
- beperkte client-shares: `Downloads`, `Movies`, `Pictures`
|
|
- lokale helper-agent op macOS
|
|
- agent registratie in WebManager
|
|
- heartbeat/status tracking
|
|
- virtuele `Clients` bron in de WebUI
|
|
- browse van remote shares
|
|
- bestand-info
|
|
- tekstpreview
|
|
- image preview waar triviaal
|
|
- download van bestanden
|
|
- nette offline-afhandeling
|
|
|
|
### Expliciet niet in V1.1
|
|
|
|
- hele homefolder
|
|
- willekeurige custom paths buiten de toegestane sharelijst
|
|
- shell/subprocess execution
|
|
- rename
|
|
- mkdir
|
|
- delete
|
|
- upload naar remote share
|
|
- bookmarks voor `/Clients/...`
|
|
- startup paths voor `/Clients/...`
|
|
- cross-source copy of move
|
|
- complete taakrunner-integratie zoals server copy/move tasks
|
|
- automatische LAN discovery
|
|
- multi-user auth met OS user mapping
|
|
|
|
---
|
|
|
|
## Gewenste gebruikerservaring
|
|
|
|
In de WebUI komt naast server-storage een extra virtuele bron:
|
|
|
|
- `/Volumes`
|
|
- `/Clients`
|
|
|
|
Onder `/Clients` ziet de gebruiker geregistreerde clients, bijvoorbeeld:
|
|
|
|
- `MacBook Pro van Jan`
|
|
- `iMac Woonkamer`
|
|
|
|
Onder een client ziet de gebruiker alleen de toegestane shares:
|
|
|
|
- `Downloads`
|
|
- `Movies`
|
|
- `Pictures`
|
|
|
|
Voor de gebruiker kan dat eruitzien als:
|
|
|
|
- `/Clients/MacBook-Pro-van-Jan/Downloads`
|
|
- `/Clients/MacBook-Pro-van-Jan/Movies`
|
|
- `/Clients/MacBook-Pro-van-Jan/Pictures`
|
|
|
|
Maar intern mag routing niet op `display_name` leunen.
|
|
|
|
Intern moet WebManager werken met een stabiele client-identiteit en een mappinglaag:
|
|
|
|
- `client_id` voor routing en opslag
|
|
- `display_name` voor weergave
|
|
- optioneel een afgeleide slug voor browse-url-presentatie
|
|
|
|
---
|
|
|
|
## Architectuuroverzicht
|
|
|
|
Er zijn drie componenten.
|
|
|
|
### 1. WebManager backend
|
|
|
|
Verantwoordelijk voor:
|
|
|
|
- registry van bekende remote clients
|
|
- status- en heartbeat-tracking
|
|
- virtuele browse-root `Clients`
|
|
- proxying van requests naar agents
|
|
- timeouts en foutafhandeling
|
|
- scheiding tussen local-source en remote-source afhandeling
|
|
|
|
### 2. WebUI frontend
|
|
|
|
Verantwoordelijk voor:
|
|
|
|
- tonen van `Clients` als extra bron
|
|
- navigeren binnen client/share paden
|
|
- offline status tonen
|
|
- requests afvuren naar gewone WebManager backend-routes
|
|
|
|
### 3. Remote helper-agent op macOS
|
|
|
|
Verantwoordelijk voor:
|
|
|
|
- toegang tot vaste lokale shares
|
|
- strikte padvalidatie binnen die shares
|
|
- simpele browse/info/read/download endpoints
|
|
- zichzelf registreren bij WebManager
|
|
- heartbeat sturen
|
|
- auth afdwingen op alle agent-endpoints
|
|
|
|
---
|
|
|
|
## Bereikbaarheidsmodel
|
|
|
|
Dit is de eerste harde productbeslissing.
|
|
|
|
### V1.1-keuze
|
|
|
|
V1.1 gaat uit van een omgeving waarin WebManager de agent rechtstreeks kan bereiken.
|
|
|
|
Dat betekent praktisch:
|
|
|
|
- dezelfde LAN
|
|
- of een expliciet configureerbaar agent-endpoint
|
|
- of een deployment waar server en client netwerkmatig direct verbonden zijn
|
|
|
|
### Waarom deze keuze
|
|
|
|
Dit is het simpelste model dat functioneel klopt zonder reverse tunnels, websockets als transportlaag, of extra relay-infrastructuur.
|
|
|
|
### Wat V1.1 niet probeert op te lossen
|
|
|
|
Deze versie garandeert niet dat een agent achter willekeurige NAT/firewall altijd bereikbaar is.
|
|
|
|
Dus:
|
|
|
|
- self-registration blijft het discoverymodel
|
|
- direct bereikbare agent-endpoint blijft het V1-transportmodel
|
|
- reverse-connect of tunnelmodellen zijn uitgesteld
|
|
|
|
### Fallback
|
|
|
|
Een handmatige endpoint override blijft toegestaan als operationele fallback, bijvoorbeeld:
|
|
|
|
- `http://192.168.1.25:8765`
|
|
|
|
Maar dat is geen hoofdmodel en geen productbelofte.
|
|
|
|
---
|
|
|
|
## Hoe de remote agent bekend wordt in WebManager
|
|
|
|
### Gekozen model: agent registreert zichzelf
|
|
|
|
De agent meldt zichzelf actief aan bij WebManager. Niet andersom.
|
|
|
|
Dat betekent:
|
|
|
|
- geen handmatig client-IP nodig als hoofdmodel
|
|
- geen server-naar-client discovery nodig
|
|
- geen afhankelijkheid van LAN-broadcasting
|
|
- geen probleem als het client-IP wisselt, zolang het geregistreerde endpoint actueel is
|
|
|
|
### Registratiestroom
|
|
|
|
Bij starten van de agent:
|
|
|
|
1. de agent leest lokale config
|
|
2. de agent bepaalt:
|
|
- `client_id`
|
|
- `display_name`
|
|
- `shares`
|
|
- `endpoint`
|
|
3. de agent registreert zich bij WebManager
|
|
4. WebManager slaat client-record op of werkt het bij
|
|
5. de agent stuurt periodieke heartbeats
|
|
|
|
### Benodigde velden bij registratie
|
|
|
|
Voorstel:
|
|
|
|
```json
|
|
{
|
|
"client_id": "f4b2c8f8-2b1b-4d89-9ed2-8d6d7b1f3abc",
|
|
"display_name": "MacBook Pro van Jan",
|
|
"platform": "macos",
|
|
"agent_version": "1.1.0",
|
|
"endpoint": "http://192.168.1.25:8765",
|
|
"shares": [
|
|
{ "key": "downloads", "label": "Downloads" },
|
|
{ "key": "movies", "label": "Movies" },
|
|
{ "key": "pictures", "label": "Pictures" }
|
|
]
|
|
}
|
|
```
|
|
|
|
### Backend bewaart per client
|
|
|
|
- `client_id`
|
|
- `display_name`
|
|
- `platform`
|
|
- `agent_version`
|
|
- `endpoint`
|
|
- `shares`
|
|
- `last_seen`
|
|
- `status`
|
|
- `last_error`
|
|
- `reachable_at`
|
|
- eventueel `registration_token_id`
|
|
|
|
### Heartbeat
|
|
|
|
De agent stuurt elke 15-30 seconden een heartbeat.
|
|
|
|
Bijvoorbeeld:
|
|
|
|
```json
|
|
{
|
|
"client_id": "f4b2c8f8-2b1b-4d89-9ed2-8d6d7b1f3abc",
|
|
"agent_version": "1.1.0"
|
|
}
|
|
```
|
|
|
|
### Statusmodel
|
|
|
|
Deze velden moeten logisch gescheiden blijven:
|
|
|
|
- `last_seen`
|
|
Laatste succesvolle heartbeat van de agent.
|
|
- `status`
|
|
Afgeleide UI-status, bijvoorbeeld `online` of `offline`.
|
|
- `last_error`
|
|
Laatste connect- of browsefout richting agent.
|
|
- `reachable_at`
|
|
Laatste moment waarop een directe agent-call echt succesvol was.
|
|
|
|
Belangrijk:
|
|
|
|
- een heartbeat bepaalt niet automatisch dat elke browse-call werkt
|
|
- een enkele browse-timeout mag niet blind `last_seen` overschrijven
|
|
- status mag niet gaan flappen op basis van één los incident
|
|
|
|
### Aanbevolen statusregels
|
|
|
|
- `online` als `last_seen` recent is
|
|
- `offline` als heartbeat-timeout overschreden is
|
|
- extra foutdetails via `last_error`
|
|
- optioneel UI-label zoals `online with recent errors` later, maar niet nodig in V1.1
|
|
|
|
---
|
|
|
|
## Authenticatie en beveiliging
|
|
|
|
### Backend registratie-auth
|
|
|
|
Registratie vereist een bearer token.
|
|
|
|
Bijvoorbeeld:
|
|
|
|
- `Authorization: Bearer <registration-token>`
|
|
|
|
### Agent endpoint-auth
|
|
|
|
Alle agent-calls vereisen authenticatie. Niet alleen registratie.
|
|
|
|
Dus ook:
|
|
|
|
- `/health`
|
|
- `/api/list`
|
|
- `/api/info`
|
|
- `/api/read`
|
|
- `/api/download`
|
|
|
|
moeten beschermd zijn.
|
|
|
|
### V1.1 minimum
|
|
|
|
Voor V1.1 volstaat een eenvoudige gedeelde agent-token, bijvoorbeeld:
|
|
|
|
- WebManager bewaart een secret per client of per installatie
|
|
- backend stuurt dat token mee op elke agent-call
|
|
- agent weigert requests zonder geldig token
|
|
|
|
Voorbeeld:
|
|
|
|
- `Authorization: Bearer <agent-access-token>`
|
|
|
|
### Niet doen in V1.1
|
|
|
|
- open agent-HTTP API zonder auth
|
|
- browse/download endpoints publiek bereikbaar maken op het LAN
|
|
|
|
---
|
|
|
|
## Virtueel padmodel
|
|
|
|
Remote client shares krijgen een aparte namespace.
|
|
|
|
Voorstel voor de gebruikersweergave:
|
|
|
|
- `/Clients`
|
|
- `/Clients/<client-display>`
|
|
- `/Clients/<client-display>/<share-label>`
|
|
- `/Clients/<client-display>/<share-label>/subdir/file.ext`
|
|
|
|
Intern moet de backend dit mappen naar:
|
|
|
|
- `client_id`
|
|
- `share_key`
|
|
- relatief share-pad
|
|
|
|
Belangrijk:
|
|
|
|
- dit zijn logische WebManager-paden
|
|
- het zijn geen echte lokale backend filesystem-paden
|
|
- ze mogen niet door de bestaande lokale `PathGuard` resolved worden
|
|
|
|
### Consequentie voor de codebasis
|
|
|
|
`/Clients/...` moet vroeg in routing worden onderschept door een aparte browse- of source-facade.
|
|
|
|
Dus:
|
|
|
|
- niet de lokale `PathGuard` uitbreiden tot remote sources
|
|
- niet overal `if remote` in bestaande lokale services strooien
|
|
- wel een duidelijke scheiding tussen local source en remote source
|
|
|
|
---
|
|
|
|
## Share-validatie in de agent
|
|
|
|
De agent werkt niet met vrije absolute paden.
|
|
|
|
De agent heeft een vaste share-map, bijvoorbeeld:
|
|
|
|
```json
|
|
{
|
|
"downloads": "/Users/jan/Downloads",
|
|
"movies": "/Users/jan/Movies",
|
|
"pictures": "/Users/jan/Pictures"
|
|
}
|
|
```
|
|
|
|
Een request bevat dan:
|
|
|
|
- `share = downloads`
|
|
- `path = Some/Subdir/file.txt`
|
|
|
|
Niet:
|
|
|
|
- `/Users/jan/...`
|
|
|
|
### Validatieregels
|
|
|
|
- onbekende `share` weigeren
|
|
- `..` weigeren
|
|
- pad resolven binnen de gekozen share-root
|
|
- symlink escape blokkeren
|
|
- alleen toegestane bestandshandelingen toestaan
|
|
|
|
---
|
|
|
|
## Read, preview en download limieten
|
|
|
|
V1.1 moet resource-grenzen expliciet vastleggen.
|
|
|
|
### Tekstpreview
|
|
|
|
- maximum grootte voor tekstpreview vastleggen
|
|
- voorstel: zelfde orde als huidige server-side preview/edit-limieten, of kleiner
|
|
- grote tekstbestanden niet volledig in memory laden voor preview
|
|
|
|
### Binary versus text
|
|
|
|
- agent moet tekstpreview alleen teruggeven voor ondersteunde teksttypes
|
|
- binaire content mag niet per ongeluk als tekst in JSON-responses worden gepusht
|
|
|
|
### Download
|
|
|
|
- downloads moeten gestreamd worden
|
|
- geen volledige bestand-buffering in memory
|
|
|
|
### Image preview
|
|
|
|
- alleen triviale image preview in V1.1
|
|
- geen zware thumbnail-pipeline in deze fase
|
|
|
|
---
|
|
|
|
## Offline gedrag
|
|
|
|
Dit is een harde eis.
|
|
|
|
WebManager mag niet vastlopen als de agent niet draait.
|
|
|
|
### Backendregels
|
|
|
|
- alle agent-calls krijgen korte timeouts, bijvoorbeeld 1-3 seconden
|
|
- connect- of timeoutfouten worden vertaald naar nette app-fouten
|
|
- offline agent blokkeert nooit globale pagina-initialisatie
|
|
- browse- en file-fouten blijven lokaal tot betreffende request
|
|
|
|
### Frontendregels
|
|
|
|
- `/Clients` mag laden, ook als sommige clients offline zijn
|
|
- offline clients mogen zichtbaar blijven in de lijst
|
|
- browsen in offline subtree toont foutmelding
|
|
- andere panes blijven bruikbaar
|
|
- geen endless spinner
|
|
|
|
---
|
|
|
|
## API-ontwerp
|
|
|
|
## 1. Backend registry endpoints
|
|
|
|
### `POST /api/clients/register`
|
|
|
|
Registreert of update een remote agent.
|
|
|
|
### `POST /api/clients/heartbeat`
|
|
|
|
Werkt `last_seen` bij.
|
|
|
|
### `GET /api/clients`
|
|
|
|
Geeft bekende clients terug met:
|
|
|
|
- `client_id`
|
|
- `display_name`
|
|
- `status`
|
|
- `last_seen`
|
|
- `last_error`
|
|
- `shares`
|
|
|
|
---
|
|
|
|
## 2. Backend browse facade voor UI
|
|
|
|
De frontend blijft praten met gewone WebManager-routes.
|
|
|
|
### `GET /api/browse?path=/Clients`
|
|
|
|
Geeft alle bekende clients terug als directories.
|
|
|
|
### `GET /api/browse?path=/Clients/<client>/`
|
|
|
|
Geeft shares van die client terug als directories.
|
|
|
|
### `GET /api/browse?path=/Clients/<client>/<share>/...`
|
|
|
|
Backend vertaalt dit naar een agent-call.
|
|
|
|
Belangrijk:
|
|
|
|
- browse facade bepaalt eerst of pad onder `/Clients` valt
|
|
- alleen niet-remote paden mogen daarna naar bestaande lokale browse-paths
|
|
|
|
---
|
|
|
|
## 3. Agent endpoints
|
|
|
|
Eenvoudig houden. Geen shell.
|
|
|
|
### `GET /health`
|
|
|
|
Gezondheidscheck met auth.
|
|
|
|
### `GET /api/list?share=downloads&path=subdir`
|
|
|
|
Directory-inhoud binnen een share.
|
|
|
|
### `GET /api/info?share=downloads&path=file.txt`
|
|
|
|
Metadata.
|
|
|
|
### `GET /api/read?share=downloads&path=file.txt`
|
|
|
|
Tekstpreview.
|
|
|
|
### `GET /api/download?share=downloads&path=file.txt`
|
|
|
|
Gestreamde download.
|
|
|
|
---
|
|
|
|
## Haalbaarheid
|
|
|
|
## Goed haalbaar in V1.1
|
|
|
|
- client registry
|
|
- heartbeat online/offline
|
|
- virtuele `Clients` root
|
|
- browse
|
|
- file info
|
|
- tekstpreview
|
|
- eenvoudige image preview
|
|
- gestreamde download
|
|
|
|
## Bewust uitgesteld
|
|
|
|
- rename
|
|
- mkdir
|
|
- delete
|
|
- upload
|
|
- bookmarks/startup paths
|
|
- cross-source copy
|
|
- cross-source move
|
|
- unified history
|
|
- task-runner integratie
|
|
|
|
---
|
|
|
|
## Veranderingen per gebied
|
|
|
|
## Backend
|
|
|
|
Nieuwe onderdelen:
|
|
|
|
- client registry repository
|
|
- client registry service
|
|
- routes voor register/heartbeat/list
|
|
- browse/source facade voor `Clients/...`
|
|
- agent HTTP client met harde timeouts en auth
|
|
|
|
Bestaande onderdelen die waarschijnlijk geraakt worden:
|
|
|
|
- [routes_browse.py](/workspace/webmanager-mvp/webui/backend/app/api/routes_browse.py)
|
|
Om `/Clients` vroeg te routeren.
|
|
- [dependencies.py](/workspace/webmanager-mvp/webui/backend/app/dependencies.py)
|
|
Voor nieuwe registry- en agent-services.
|
|
- [app/main.py](/workspace/webmanager-mvp/webui/backend/app/main.py)
|
|
Voor nieuwe routers.
|
|
|
|
Liever niet verbreden:
|
|
|
|
- [path_guard.py](/workspace/webmanager-mvp/webui/backend/app/security/path_guard.py)
|
|
Deze hoort lokaal filesystemgericht te blijven.
|
|
- [file_ops_service.py](/workspace/webmanager-mvp/webui/backend/app/services/file_ops_service.py)
|
|
Deze service is nu server-filesystemgericht en moet niet vervuild raken met remote transportlogica.
|
|
|
|
## Frontend
|
|
|
|
Waarschijnlijk aanpassen:
|
|
|
|
- [app.js](/workspace/webmanager-mvp/webui/html/app.js)
|
|
Voor:
|
|
- extra virtuele root
|
|
- render van clients en shares
|
|
- offline status
|
|
- source-aware browse/view/download/info flows
|
|
- [index.html](/workspace/webmanager-mvp/webui/html/index.html)
|
|
Alleen als extra statuslabels of clientindicatoren nodig zijn
|
|
|
|
## Remote agent
|
|
|
|
Te baseren op:
|
|
|
|
- [finder_commander/app/main.py](/workspace/webmanager-mvp/finder_commander/app/main.py)
|
|
- [finder_commander/run-local.sh](/workspace/webmanager-mvp/finder_commander/run-local.sh)
|
|
- [finder_commander/requirements.txt](/workspace/webmanager-mvp/finder_commander/requirements.txt)
|
|
|
|
Maar vereenvoudigd:
|
|
|
|
- geen shell command endpoint
|
|
- geen hele home-root
|
|
- alleen `share key + relatief pad`
|
|
- registratie en heartbeat toevoegen
|
|
- auth afdwingen op alle endpoints
|
|
|
|
---
|
|
|
|
## Minimale agent-config
|
|
|
|
Voorstel lokaal configbestand:
|
|
|
|
```json
|
|
{
|
|
"webmanager_base_url": "https://webmanager.example.com",
|
|
"registration_token": "registration-secret",
|
|
"agent_access_token": "agent-secret",
|
|
"client_id": "f4b2c8f8-2b1b-4d89-9ed2-8d6d7b1f3abc",
|
|
"display_name": "MacBook Pro van Jan",
|
|
"shares": {
|
|
"downloads": "/Users/jan/Downloads",
|
|
"movies": "/Users/jan/Movies",
|
|
"pictures": "/Users/jan/Pictures"
|
|
},
|
|
"listen_host": "0.0.0.0",
|
|
"listen_port": 8765,
|
|
"public_endpoint": "http://192.168.1.25:8765"
|
|
}
|
|
```
|
|
|
|
Opmerking:
|
|
|
|
- `public_endpoint` is het endpoint dat WebManager gebruikt
|
|
- `listen_host` en `public_endpoint` hoeven niet identiek te zijn
|
|
|
|
---
|
|
|
|
## Open keuzes die bewust zijn uitgesteld
|
|
|
|
Deze keuzes zijn echt later werk, niet meer V1.1:
|
|
|
|
- reverse-connect of tunnelmodel
|
|
- cross-source copy
|
|
- cross-source move
|
|
- bookmarks/startup paths voor `/Clients/...`
|
|
- write-acties op remote shares
|
|
- sterkere pairing of key rotation
|
|
|
|
---
|
|
|
|
## Beslisadvies
|
|
|
|
Aanbevolen implementatievolgorde voor V1.1:
|
|
|
|
1. agent registry + heartbeat
|
|
2. virtuele `Clients` root in browse
|
|
3. online/offline status met gescheiden statusvelden
|
|
4. browse/info/preview/download voor remote shares
|
|
|
|
Niet in V1.1:
|
|
|
|
5. write-acties
|
|
6. bookmarks/startup paths
|
|
7. cross-source flows
|
|
|
|
---
|
|
|
|
## Samenvatting
|
|
|
|
De juiste V1.1-richting is:
|
|
|
|
- geen hele homefolder
|
|
- wel beperkte shares zoals `Downloads`, `Movies`, `Pictures`
|
|
- remote helper-agent op macOS
|
|
- agent registreert zichzelf bij WebManager
|
|
- WebManager bewaart `client_id`-geleide registry en status
|
|
- `/Clients` wordt een aparte virtuele bron
|
|
- remote paden blijven buiten lokale filesystem services
|
|
- alle agent-calls vereisen auth
|
|
- offline agents mogen nooit de rest van WebManager verstoren
|
|
|
|
Dit model is haalbaar, beperkt in scope, en houdt de bestaande lokale storage-architectuur schoon.
|