Files
webmanager-mvp/project_docs/REMOTE_CLIENT_SHARES_V1_DESIGN.md
T
2026-03-25 18:21:54 +01:00

16 KiB

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:

{
  "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:

{
  "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:

{
  "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:

Liever niet verbreden:

  • path_guard.py Deze hoort lokaal filesystemgericht te blijven.
  • file_ops_service.py Deze service is nu server-filesystemgericht en moet niet vervuild raken met remote transportlogica.

Frontend

Waarschijnlijk aanpassen:

  • app.js Voor:
    • extra virtuele root
    • render van clients en shares
    • offline status
    • source-aware browse/view/download/info flows
  • index.html Alleen als extra statuslabels of clientindicatoren nodig zijn

Remote agent

Te baseren op:

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:

{
  "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:

  1. write-acties
  2. bookmarks/startup paths
  3. 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.